aboutsummaryrefslogtreecommitdiff
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig26
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/agp/ali-agp.c2
-rw-r--r--drivers/char/agp/alpha-agp.c2
-rw-r--r--drivers/char/agp/amd64-agp.c13
-rw-r--r--drivers/char/agp/generic.c22
-rw-r--r--drivers/char/agp/intel-agp.c8
-rw-r--r--drivers/char/agp/nvidia-agp.c9
-rw-r--r--drivers/char/agp/parisc-agp.c2
-rw-r--r--drivers/char/agp/sgi-agp.c5
-rw-r--r--drivers/char/agp/sis-agp.c278
-rw-r--r--drivers/char/agp/sworks-agp.c23
-rw-r--r--drivers/char/agp/uninorth-agp.c2
-rw-r--r--drivers/char/amiserial.c4
-rw-r--r--drivers/char/briq_panel.c2
-rw-r--r--drivers/char/consolemap.c6
-rw-r--r--drivers/char/cs5535_gpio.c1
-rw-r--r--drivers/char/cyclades.c2581
-rw-r--r--drivers/char/digi.h71
-rw-r--r--drivers/char/drm/README.drm16
-rw-r--r--drivers/char/drm/ati_pcigart.c84
-rw-r--r--drivers/char/drm/drm.h4
-rw-r--r--drivers/char/drm/drmP.h30
-rw-r--r--drivers/char/drm/drm_bufs.c75
-rw-r--r--drivers/char/drm/drm_dma.c2
-rw-r--r--drivers/char/drm/drm_drv.c15
-rw-r--r--drivers/char/drm/drm_fops.c96
-rw-r--r--drivers/char/drm/drm_hashtab.c17
-rw-r--r--drivers/char/drm/drm_hashtab.h1
-rw-r--r--drivers/char/drm/drm_irq.c4
-rw-r--r--drivers/char/drm/drm_lock.c134
-rw-r--r--drivers/char/drm/drm_mm.c2
-rw-r--r--drivers/char/drm/drm_os_linux.h3
-rw-r--r--drivers/char/drm/drm_pciids.h4
-rw-r--r--drivers/char/drm/drm_proc.c2
-rw-r--r--drivers/char/drm/drm_stub.c1
-rw-r--r--drivers/char/drm/drm_vm.c104
-rw-r--r--drivers/char/drm/i915_dma.c3
-rw-r--r--drivers/char/drm/r128_cce.c3
-rw-r--r--drivers/char/drm/r128_drv.h2
-rw-r--r--drivers/char/drm/r300_reg.h2
-rw-r--r--drivers/char/drm/radeon_cp.c79
-rw-r--r--drivers/char/drm/radeon_drm.h1
-rw-r--r--drivers/char/drm/radeon_drv.h24
-rw-r--r--drivers/char/drm/radeon_state.c52
-rw-r--r--drivers/char/drm/sis_drv.c2
-rw-r--r--drivers/char/drm/via_dma.c111
-rw-r--r--drivers/char/drm/via_drv.c3
-rw-r--r--drivers/char/drm/via_drv.h5
-rw-r--r--drivers/char/drm/via_mm.h40
-rw-r--r--drivers/char/ds1620.c1
-rw-r--r--drivers/char/dsp56k.c1
-rw-r--r--drivers/char/dtlk.c15
-rw-r--r--drivers/char/ec3104_keyb.c1
-rw-r--r--drivers/char/epca.c2
-rw-r--r--drivers/char/genrtc.c6
-rw-r--r--drivers/char/hangcheck-timer.c1
-rw-r--r--drivers/char/hvc_console.c12
-rw-r--r--drivers/char/hvc_iseries.c2
-rw-r--r--drivers/char/hvc_vio.c2
-rw-r--r--drivers/char/hw_random/Kconfig14
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/intel-rng.c219
-rw-r--r--drivers/char/hw_random/pasemi-rng.c156
-rw-r--r--drivers/char/hw_random/via-rng.c1
-rw-r--r--drivers/char/i8k.c1
-rw-r--r--drivers/char/ip27-rtc.c1
-rw-r--r--drivers/char/ipmi/Kconfig2
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c235
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c136
-rw-r--r--drivers/char/isicom.c3
-rw-r--r--drivers/char/keyboard.c103
-rw-r--r--drivers/char/lp.c8
-rw-r--r--drivers/char/mem.c9
-rw-r--r--drivers/char/misc.c27
-rw-r--r--drivers/char/mmtimer.c4
-rw-r--r--drivers/char/moxa.c8
-rw-r--r--drivers/char/mxser.c1
-rw-r--r--drivers/char/mxser_new.c1
-rw-r--r--drivers/char/n_r3964.c4
-rw-r--r--drivers/char/n_tty.c29
-rw-r--r--drivers/char/pcmcia/Kconfig1
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c46
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c7
-rw-r--r--drivers/char/pcmcia/synclink_cs.c1
-rw-r--r--drivers/char/ppdev.c3
-rw-r--r--drivers/char/rio/riocmd.c2
-rw-r--r--drivers/char/riscom8.c2
-rw-r--r--drivers/char/rocket.c36
-rw-r--r--drivers/char/rocket_int.h6
-rw-r--r--drivers/char/rtc.c2
-rw-r--r--drivers/char/selection.c2
-rw-r--r--drivers/char/serial167.c2
-rw-r--r--drivers/char/synclink.c7
-rw-r--r--drivers/char/synclink_gt.c141
-rw-r--r--drivers/char/sysrq.c1
-rw-r--r--drivers/char/tipar.c2
-rw-r--r--drivers/char/tpm/Kconfig3
-rw-r--r--drivers/char/tpm/tpm.c36
-rw-r--r--drivers/char/tpm/tpm.h6
-rw-r--r--drivers/char/tpm/tpm_atmel.h4
-rw-r--r--drivers/char/tpm/tpm_infineon.c231
-rw-r--r--drivers/char/tty_io.c123
-rw-r--r--drivers/char/vc_screen.c19
-rw-r--r--drivers/char/vt.c304
-rw-r--r--drivers/char/vt_ioctl.c2
-rw-r--r--drivers/char/watchdog/omap_wdt.c1
-rw-r--r--drivers/char/watchdog/sc1200wdt.c1
-rw-r--r--drivers/char/watchdog/scx200_wdt.c2
109 files changed, 3298 insertions, 2681 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index d0c978fbc20..abcafac6473 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -6,6 +6,7 @@ menu "Character devices"
config VT
bool "Virtual terminal" if EMBEDDED
+ depends on !S390
select INPUT
default y if !VIOCONS
---help---
@@ -81,6 +82,7 @@ config VT_HW_CONSOLE_BINDING
config SERIAL_NONSTANDARD
bool "Non-standard serial port support"
+ depends on HAS_IOMEM
---help---
Say Y here if you have any non-standard serial boards -- boards
which aren't supported using the standard "dumb" serial driver.
@@ -127,7 +129,7 @@ config ROCKETPORT
config CYCLADES
tristate "Cyclades async mux support"
- depends on SERIAL_NONSTANDARD
+ depends on SERIAL_NONSTANDARD && (PCI || ISA)
---help---
This driver supports Cyclades Z and Y multiserial boards.
You would need something like this to connect more than two modems to
@@ -631,7 +633,8 @@ config HVC_CONSOLE
config HVC_ISERIES
bool "iSeries Hypervisor Virtual Console support"
- depends on PPC_ISERIES && !VIOCONS
+ depends on PPC_ISERIES
+ default y
select HVC_DRIVER
help
iSeries machines support a hypervisor virtual console.
@@ -764,7 +767,7 @@ config NVRAM
config RTC
tristate "Enhanced Real Time Clock Support"
- depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH
+ depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
---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
@@ -812,7 +815,7 @@ config SGI_IP27_RTC
config GEN_RTC
tristate "Generic /dev/rtc emulation"
- depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV
+ depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV && !S390
---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
@@ -857,6 +860,7 @@ config COBALT_LCD
config DTLK
tristate "Double Talk PC internal speech card support"
+ depends on ISA
help
This driver is for the DoubleTalk PC, a speech synthesizer
manufactured by RC Systems (<http://www.rcsys.com/>). It is also
@@ -905,8 +909,8 @@ config SONYPI
To compile this driver as a module, choose M here: the
module will be called sonypi.
-config TANBAC_TB0219
- tristate "TANBAC TB0219 base board support"
+config GPIO_TB0219
+ tristate "TANBAC TB0219 GPIO support"
depends on TANBAC_TB022X
select GPIO_VR41XX
@@ -1042,7 +1046,7 @@ config HPET_MMAP
config HANGCHECK_TIMER
tristate "Hangcheck timer"
- depends on X86 || IA64 || PPC64
+ depends on X86 || IA64 || PPC64 || S390
help
The hangcheck-timer module detects when the system has gone
out to lunch past a certain margin. It can reboot the system
@@ -1071,5 +1075,13 @@ config TELCLOCK
/sys/devices/platform/telco_clock, with a number of files for
controlling the behavior of this hardware.
+config DEVPORT
+ bool
+ depends on !M68K
+ depends on ISA || PCI
+ default y
+
+source "drivers/s390/char/Kconfig"
+
endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index ae8567cc529..2f56ecc035a 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -91,7 +91,7 @@ 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_TANBAC_TB0219) += tb0219.o
+obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
obj-$(CONFIG_WATCHDOG) += watchdog/
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index 5b684fddcc0..4941ddb7893 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -145,6 +145,7 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge)
void *addr = agp_generic_alloc_page(agp_bridge);
u32 temp;
+ global_flush_tlb();
if (!addr)
return NULL;
@@ -160,6 +161,7 @@ static void ali_destroy_page(void * addr)
if (addr) {
global_cache_flush(); /* is this really needed? --hch */
agp_generic_destroy_page(addr);
+ global_flush_tlb();
}
}
diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
index b0acf41c0db..aa8f3a39a70 100644
--- a/drivers/char/agp/alpha-agp.c
+++ b/drivers/char/agp/alpha-agp.c
@@ -173,7 +173,7 @@ alpha_core_agp_setup(void)
/*
* Build a fake pci_dev struct
*/
- pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+ pdev = alloc_pci_dev();
if (!pdev)
return -ENOMEM;
pdev->vendor = 0xffff;
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 485720486d6..c9f0f250d78 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -14,6 +14,7 @@
#include <linux/agp_backend.h>
#include <linux/mmzone.h>
#include <asm/page.h> /* PAGE_SIZE */
+#include <asm/e820.h>
#include <asm/k8.h>
#include "agp.h"
@@ -259,7 +260,6 @@ static const struct agp_bridge_driver amd_8151_driver = {
/* Some basic sanity checks for the aperture. */
static int __devinit aperture_valid(u64 aper, u32 size)
{
- u32 pfn, c;
if (aper == 0) {
printk(KERN_ERR PFX "No aperture\n");
return 0;
@@ -272,14 +272,9 @@ static int __devinit aperture_valid(u64 aper, u32 size)
printk(KERN_ERR PFX "Aperture out of bounds\n");
return 0;
}
- pfn = aper >> PAGE_SHIFT;
- for (c = 0; c < size/PAGE_SIZE; c++) {
- if (!pfn_valid(pfn + c))
- break;
- if (!PageReserved(pfn_to_page(pfn + c))) {
- printk(KERN_ERR PFX "Aperture pointing to RAM\n");
- return 0;
- }
+ if (e820_any_mapped(aper, aper + size, E820_RAM)) {
+ printk(KERN_ERR PFX "Aperture pointing to RAM\n");
+ return 0;
}
/* Request the Aperture. This catches cases when someone else
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index f902d71947b..45aeb917ec6 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -51,28 +51,6 @@ int agp_memory_reserved;
*/
EXPORT_SYMBOL_GPL(agp_memory_reserved);
-#if defined(CONFIG_X86)
-int map_page_into_agp(struct page *page)
-{
- int i;
- i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE);
- /* Caller's responsibility to call global_flush_tlb() for
- * performance reasons */
- return i;
-}
-EXPORT_SYMBOL_GPL(map_page_into_agp);
-
-int unmap_page_from_agp(struct page *page)
-{
- int i;
- i = change_page_attr(page, 1, PAGE_KERNEL);
- /* Caller's responsibility to call global_flush_tlb() for
- * performance reasons */
- return i;
-}
-EXPORT_SYMBOL_GPL(unmap_page_from_agp);
-#endif
-
/*
* Generic routines for handling agp_memory structures -
* They use the basic page allocation routines to do the brunt of the work.
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 55392a45a14..9c69f2e761f 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -186,8 +186,9 @@ static void *i8xx_alloc_pages(void)
return NULL;
if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) {
+ change_page_attr(page, 4, PAGE_KERNEL);
global_flush_tlb();
- __free_page(page);
+ __free_pages(page, 2);
return NULL;
}
global_flush_tlb();
@@ -209,7 +210,7 @@ static void i8xx_destroy_pages(void *addr)
global_flush_tlb();
put_page(page);
unlock_page(page);
- free_pages((unsigned long)addr, 2);
+ __free_pages(page, 2);
atomic_dec(&agp_bridge->current_memory_agp);
}
@@ -315,9 +316,6 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
struct agp_memory *new;
void *addr;
- if (pg_count != 1 && pg_count != 4)
- return NULL;
-
switch (pg_count) {
case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge);
global_flush_tlb();
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 0c9dab557c9..6cd7373dcdf 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -320,11 +320,11 @@ static int __devinit agp_nvidia_probe(struct pci_dev *pdev,
u8 cap_ptr;
nvidia_private.dev_1 =
- pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1));
+ pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1));
nvidia_private.dev_2 =
- pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2));
+ pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2));
nvidia_private.dev_3 =
- pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0));
+ pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0));
if (!nvidia_private.dev_1 || !nvidia_private.dev_2 || !nvidia_private.dev_3) {
printk(KERN_INFO PFX "Detected an NVIDIA nForce/nForce2 "
@@ -443,6 +443,9 @@ static int __init agp_nvidia_init(void)
static void __exit agp_nvidia_cleanup(void)
{
pci_unregister_driver(&agp_nvidia_pci_driver);
+ pci_dev_put(nvidia_private.dev_1);
+ pci_dev_put(nvidia_private.dev_2);
+ pci_dev_put(nvidia_private.dev_3);
}
module_init(agp_nvidia_init);
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 3d83b461cca..f4562cc2234 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -329,7 +329,7 @@ parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
struct agp_bridge_data *bridge;
int error = 0;
- fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+ fake_bridge_dev = alloc_pci_dev();
if (!fake_bridge_dev) {
error = -ENOMEM;
goto fail;
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index ee8f50edde1..cda608c42be 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -47,9 +47,8 @@ static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
nid = info->ca_closest_node;
page = alloc_pages_node(nid, GFP_KERNEL, 0);
- if (page == NULL) {
- return 0;
- }
+ if (!page)
+ return NULL;
get_page(page);
SetPageLocked(page);
diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
index 125f4282d95..eb1a1c73819 100644
--- a/drivers/char/agp/sis-agp.c
+++ b/drivers/char/agp/sis-agp.c
@@ -143,96 +143,6 @@ static struct agp_bridge_driver sis_driver = {
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
};
-static struct agp_device_ids sis_agp_device_ids[] __devinitdata =
-{
- {
- .device_id = PCI_DEVICE_ID_SI_5591_AGP,
- .chipset_name = "5591",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_530,
- .chipset_name = "530",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_540,
- .chipset_name = "540",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_550,
- .chipset_name = "550",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_620,
- .chipset_name = "620",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_630,
- .chipset_name = "630",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_635,
- .chipset_name = "635",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_645,
- .chipset_name = "645",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_646,
- .chipset_name = "646",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_648,
- .chipset_name = "648",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_650,
- .chipset_name = "650",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_651,
- .chipset_name = "651",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_655,
- .chipset_name = "655",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_661,
- .chipset_name = "661",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_730,
- .chipset_name = "730",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_735,
- .chipset_name = "735",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_740,
- .chipset_name = "740",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_741,
- .chipset_name = "741",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_745,
- .chipset_name = "745",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_746,
- .chipset_name = "746",
- },
- {
- .device_id = PCI_DEVICE_ID_SI_760,
- .chipset_name = "760",
- },
- { }, /* dummy final entry, always present */
-};
-
-
// chipsets that require the 'delay hack'
static int sis_broken_chipsets[] __devinitdata = {
PCI_DEVICE_ID_SI_648,
@@ -269,29 +179,15 @@ static void __devinit sis_get_driver(struct agp_bridge_data *bridge)
static int __devinit agp_sis_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- struct agp_device_ids *devs = sis_agp_device_ids;
struct agp_bridge_data *bridge;
u8 cap_ptr;
- int j;
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
if (!cap_ptr)
return -ENODEV;
- /* probe for known chipsets */
- for (j = 0; devs[j].chipset_name; j++) {
- if (pdev->device == devs[j].device_id) {
- printk(KERN_INFO PFX "Detected SiS %s chipset\n",
- devs[j].chipset_name);
- goto found;
- }
- }
-
- printk(KERN_ERR PFX "Unsupported SiS chipset (device id: %04x)\n",
- pdev->device);
- return -ENODEV;
-found:
+ printk(KERN_INFO PFX "Detected SiS chipset - id:%i\n", pdev->device);
bridge = agp_alloc_bridge();
if (!bridge)
return -ENOMEM;
@@ -320,12 +216,172 @@ static void __devexit agp_sis_remove(struct pci_dev *pdev)
static struct pci_device_id agp_sis_pci_table[] = {
{
- .class = (PCI_CLASS_BRIDGE_HOST << 8),
- .class_mask = ~0,
- .vendor = PCI_VENDOR_ID_SI,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_5591_AGP,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_530,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_540,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_550,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_620,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_630,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_635,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_645,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_646,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_648,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_650,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_651,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_655,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_661,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_730,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_735,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_740,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_741,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_745,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_746,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_760,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
},
{ }
};
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 55212a3811f..551ef25063e 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -455,15 +455,6 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
u32 temp, temp2;
u8 cap_ptr = 0;
- /* Everything is on func 1 here so we are hardcoding function one */
- bridge_dev = pci_find_slot((unsigned int)pdev->bus->number,
- PCI_DEVFN(0, 1));
- if (!bridge_dev) {
- printk(KERN_INFO PFX "Detected a Serverworks chipset "
- "but could not find the secondary device.\n");
- return -ENODEV;
- }
-
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
switch (pdev->device) {
@@ -483,6 +474,15 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
return -ENODEV;
}
+ /* Everything is on func 1 here so we are hardcoding function one */
+ bridge_dev = pci_get_bus_and_slot((unsigned int)pdev->bus->number,
+ PCI_DEVFN(0, 1));
+ if (!bridge_dev) {
+ printk(KERN_INFO PFX "Detected a Serverworks chipset "
+ "but could not find the secondary device.\n");
+ return -ENODEV;
+ }
+
serverworks_private.svrwrks_dev = bridge_dev;
serverworks_private.gart_addr_ofs = 0x10;
@@ -515,7 +515,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev,
bridge->driver = &sworks_driver;
bridge->dev_private_data = &serverworks_private,
- bridge->dev = pdev;
+ bridge->dev = pci_dev_get(pdev);
pci_set_drvdata(pdev, bridge);
return agp_add_bridge(bridge);
@@ -525,8 +525,11 @@ static void __devexit agp_serverworks_remove(struct pci_dev *pdev)
{
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+ pci_dev_put(bridge->dev);
agp_remove_bridge(bridge);
agp_put_bridge(bridge);
+ pci_dev_put(serverworks_private.svrwrks_dev);
+ serverworks_private.svrwrks_dev = NULL;
}
static struct pci_device_id agp_serverworks_pci_table[] = {
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 91b062126a6..42c0a600b1a 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -613,7 +613,7 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
uninorth_node = of_find_node_by_name(NULL, "u3");
}
if (uninorth_node) {
- const int *revprop = get_property(uninorth_node,
+ const int *revprop = of_get_property(uninorth_node,
"device-rev", NULL);
if (revprop != NULL)
uninorth_rev = *revprop & 0x3f;
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 0e2b72f2b88..4eaceabd8ce 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -1574,7 +1574,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
@@ -1700,7 +1700,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
#endif
schedule();
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
if (extra_count)
state->count++;
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
index c70d52ace8b..ed53f541d9e 100644
--- a/drivers/char/briq_panel.c
+++ b/drivers/char/briq_panel.c
@@ -206,7 +206,7 @@ static int __init briq_panel_init(void)
const char *machine;
int i;
- machine = get_property(root, "model", NULL);
+ machine = of_get_property(root, "model", NULL);
if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0) {
of_node_put(root);
return -ENODEV;
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index b99b7561260..fd40b959afd 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -626,10 +626,10 @@ conv_uni_to_pc(struct vc_data *conp, long ucs)
/* Only 16-bit codes supported at this time */
if (ucs > 0xffff)
- ucs = 0xfffd; /* U+FFFD: REPLACEMENT CHARACTER */
- else if (ucs < 0x20 || ucs >= 0xfffe)
+ return -4; /* Not found */
+ else if (ucs < 0x20)
return -1; /* Not a printable character */
- else if (ucs == 0xfeff || (ucs >= 0x200a && ucs <= 0x200f))
+ else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f))
return -2; /* Zero-width space */
/*
* UNI_DIRECT_BASE indicates the start of the region in the User Zone
diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c
index c02d9e99e05..fe6d2407bae 100644
--- a/drivers/char/cs5535_gpio.c
+++ b/drivers/char/cs5535_gpio.c
@@ -44,6 +44,7 @@ static struct pci_device_id divil_pci[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) },
{ } /* NULL entry */
};
+MODULE_DEVICE_TABLE(pci, divil_pci);
static struct cdev cs5535_gpio_cdev;
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 16dc5d1d3cb..c72ee97d389 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -10,15 +10,14 @@
*
* Initially written by Randolph Bentson <bentson@grieg.seaslug.org>.
* Modified and maintained by Marcio Saito <marcio@cyclades.com>.
- * Currently maintained by Cyclades team <async@cyclades.com>.
*
- * For Technical support and installation problems, please send e-mail
- * to support@cyclades.com.
+ * Copyright (C) 2007 Jiri Slaby <jirislaby@gmail.com>
*
* Much of the design and some of the code came from serial.c
* which was copyright (C) 1991, 1992 Linus Torvalds. It was
* extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92,
* and then fixed as suggested by Michael K. Johnson 12/12/92.
+ * Converted to pci probing and cleaned up by Jiri Slaby.
*
* This version supports shared IRQ's (only for PCI boards).
*
@@ -591,7 +590,7 @@
*
*/
-#define CY_VERSION "2.4"
+#define CY_VERSION "2.5"
/* If you need to install more boards than NR_CARDS, change the constant
in the definition below. No other change is necessary to support up to
@@ -624,12 +623,6 @@
#undef CY_ENABLE_MONITORING
#undef CY_PCI_DEBUG
-#if 0
-#define PAUSE __asm__("nop")
-#else
-#define PAUSE do {} while (0)
-#endif
-
/*
* Include section
*/
@@ -659,17 +652,6 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
-#define CY_LOCK(info,flags) \
- do { \
- spin_lock_irqsave(&cy_card[info->card].card_lock, flags); \
- } while (0)
-
-#define CY_UNLOCK(info,flags) \
- do { \
- spin_unlock_irqrestore(&cy_card[info->card].card_lock, flags); \
- } while (0)
-
-#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -682,13 +664,13 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
#define IS_CYC_Z(card) ((card).num_chips == -1)
#define Z_FPGA_CHECK(card) \
- ((cy_readl(&((struct RUNTIME_9060 __iomem *) \
+ ((readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
-#define ISZLOADED(card) (((ZO_V1==cy_readl(&((struct RUNTIME_9060 __iomem *) \
+#define ISZLOADED(card) (((ZO_V1==readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->mail_box_0)) || \
Z_FPGA_CHECK(card)) && \
- (ZFIRM_ID==cy_readl(&((struct FIRM_ID __iomem *) \
+ (ZFIRM_ID==readl(&((struct FIRM_ID __iomem *) \
((card).base_addr+ID_ADDRESS))->signature)))
#ifndef SERIAL_XMIT_SIZE
@@ -725,8 +707,8 @@ static unsigned int cy_isa_addresses[] = {
#define NR_ISA_ADDRS ARRAY_SIZE(cy_isa_addresses)
#ifdef MODULE
-static long maddr[NR_CARDS] = { 0, };
-static int irq[NR_CARDS] = { 0, };
+static long maddr[NR_CARDS];
+static int irq[NR_CARDS];
module_param_array(maddr, long, NULL, 0);
module_param_array(irq, int, NULL, 0);
@@ -739,11 +721,6 @@ module_param_array(irq, int, NULL, 0);
*/
static struct cyclades_card cy_card[NR_CARDS];
-/* This is the per-channel data structure containing pointers, flags
- and variables for the port. This driver supports a maximum of NR_PORTS.
-*/
-static struct cyclades_port cy_port[NR_PORTS];
-
static int cy_next_channel; /* next minor available */
/*
@@ -825,9 +802,6 @@ static int cy_chip_offset[] = { 0x0000,
/* PCI related definitions */
-static unsigned short cy_pci_nboard;
-static unsigned short cy_isa_nboard;
-static unsigned short cy_nboard;
#ifdef CONFIG_PCI
static struct pci_device_id cy_pci_dev_id[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI < 1Mb */
@@ -845,7 +819,7 @@ MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
static void cy_start(struct tty_struct *);
static void set_line_char(struct cyclades_port *);
-static int cyz_issue_cmd(struct cyclades_card *, uclong, ucchar, uclong);
+static int cyz_issue_cmd(struct cyclades_card *, __u32, __u8, __u32);
#ifdef CONFIG_ISA
static unsigned detect_isa_irq(void __iomem *);
#endif /* CONFIG_ISA */
@@ -858,7 +832,6 @@ static void cyz_poll(unsigned long);
/* The Cyclades-Z polling cycle is defined by this variable */
static long cyz_polling_cycle = CZ_DEF_POLL;
-static int cyz_timeron = 0;
static DEFINE_TIMER(cyz_timerlist, cyz_poll, 0, 0);
#else /* CONFIG_CYZ_INTR */
@@ -871,21 +844,14 @@ static inline int serial_paranoia_check(struct cyclades_port *info,
{
#ifdef SERIAL_PARANOIA_CHECK
if (!info) {
- printk("cyc Warning: null cyclades_port for (%s) in %s\n",
- name, routine);
- return 1;
- }
-
- if ((long)info < (long)(&cy_port[0]) ||
- (long)(&cy_port[NR_PORTS]) < (long)info) {
- printk("cyc Warning: cyclades_port out of range for (%s) in "
- "%s\n", name, routine);
+ printk(KERN_WARNING "cyc Warning: null cyclades_port for (%s) "
+ "in %s\n", name, routine);
return 1;
}
if (info->magic != CYCLADES_MAGIC) {
- printk("cyc Warning: bad magic number for serial struct (%s) "
- "in %s\n", name, routine);
+ printk(KERN_WARNING "cyc Warning: bad magic number for serial "
+ "struct (%s) in %s\n", name, routine);
return 1;
}
#endif
@@ -943,22 +909,16 @@ do_softint(struct work_struct *work)
if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event))
wake_up_interruptible(&info->open_wait);
#ifdef CONFIG_CYZ_INTR
- if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event)) {
- if (cyz_rx_full_timer[info->line].function == NULL) {
- cyz_rx_full_timer[info->line].expires = jiffies + 1;
- cyz_rx_full_timer[info->line].function = cyz_rx_restart;
- cyz_rx_full_timer[info->line].data =
- (unsigned long)info;
- add_timer(&cyz_rx_full_timer[info->line]);
- }
- }
+ if (test_and_clear_bit(Cy_EVENT_Z_RX_FULL, &info->event) &&
+ !timer_pending(&cyz_rx_full_timer[info->line]))
+ mod_timer(&cyz_rx_full_timer[info->line], jiffies + 1);
#endif
if (test_and_clear_bit(Cy_EVENT_DELTA_WAKEUP, &info->event))
wake_up_interruptible(&info->delta_msr_wait);
tty_wakeup(tty);
#ifdef Z_WAKE
if (test_and_clear_bit(Cy_EVENT_SHUTDOWN_WAKEUP, &info->event))
- wake_up_interruptible(&info->shutdown_wait);
+ complete(&info->shutdown_wait);
#endif
} /* do_softint */
@@ -975,11 +935,11 @@ do_softint(struct work_struct *work)
*/
static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
{
- volatile int i;
+ unsigned int i;
/* Check to see that the previous command has completed */
for (i = 0; i < 100; i++) {
- if (cy_readb(base_addr + (CyCCR << index)) == 0) {
+ if (readb(base_addr + (CyCCR << index)) == 0) {
break;
}
udelay(10L);
@@ -1022,7 +982,7 @@ static unsigned detect_isa_irq(void __iomem * address)
cy_writeb(address + (CyCAR << index), 0);
cy_writeb(address + (CySRER << index),
- cy_readb(address + (CySRER << index)) | CyTxRdy);
+ readb(address + (CySRER << index)) | CyTxRdy);
local_irq_restore(flags);
/* Wait ... */
@@ -1032,11 +992,11 @@ static unsigned detect_isa_irq(void __iomem * address)
irq = probe_irq_off(irqs);
/* Clean up */
- save_xir = (u_char) cy_readb(address + (CyTIR << index));
- save_car = cy_readb(address + (CyCAR << index));
+ save_xir = (u_char) readb(address + (CyTIR << index));
+ save_car = readb(address + (CyCAR << index));
cy_writeb(address + (CyCAR << index), (save_xir & 0x3));
cy_writeb(address + (CySRER << index),
- cy_readb(address + (CySRER << index)) & ~CyTxRdy);
+ readb(address + (CySRER << index)) & ~CyTxRdy);
cy_writeb(address + (CyTIR << index), (save_xir & 0x3f));
cy_writeb(address + (CyCAR << index), (save_car));
cy_writeb(address + (Cy_ClrIntr << index), 0);
@@ -1051,45 +1011,43 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
{
struct cyclades_port *info;
struct tty_struct *tty;
- volatile int char_count;
- int i, j, len, mdm_change, mdm_status, outch;
+ int char_count;
+ int j, len, mdm_change, mdm_status, outch;
int save_xir, channel, save_car;
char data;
if (status & CySRReceive) { /* reception interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: rcvd intr, chip %d\n\r", chip);
+ printk(KERN_DEBUG "cyy_interrupt: rcvd intr, chip %d\n", chip);
#endif
/* determine the channel & change to that context */
spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr + (CyRIR << index));
+ save_xir = (u_char) readb(base_addr + (CyRIR << index));
channel = (u_short) (save_xir & CyIRChannel);
- i = channel + chip * 4 + cinfo->first_line;
- info = &cy_port[i];
- info->last_active = jiffies;
- save_car = cy_readb(base_addr + (CyCAR << index));
+ info = &cinfo->ports[channel + chip * 4];
+ save_car = readb(base_addr + (CyCAR << index));
cy_writeb(base_addr + (CyCAR << index), save_xir);
/* if there is nowhere to put the data, discard it */
- if (info->tty == 0) {
- j = (cy_readb(base_addr + (CyRIVR << index)) &
+ if (info->tty == NULL) {
+ j = (readb(base_addr + (CyRIVR << index)) &
CyIVRMask);
if (j == CyIVRRxEx) { /* exception */
- data = cy_readb(base_addr + (CyRDSR << index));
+ data = readb(base_addr + (CyRDSR << index));
} else { /* normal character reception */
- char_count = cy_readb(base_addr +
+ char_count = readb(base_addr +
(CyRDCR << index));
while (char_count--) {
- data = cy_readb(base_addr +
+ data = readb(base_addr +
(CyRDSR << index));
}
}
} else { /* there is an open port for this data */
tty = info->tty;
- j = (cy_readb(base_addr + (CyRIVR << index)) &
+ j = (readb(base_addr + (CyRIVR << index)) &
CyIVRMask);
if (j == CyIVRRxEx) { /* exception */
- data = cy_readb(base_addr + (CyRDSR << index));
+ data = readb(base_addr + (CyRDSR << index));
/* For statistics only */
if (data & CyBREAK)
@@ -1110,7 +1068,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
if (data & CyBREAK) {
tty_insert_flip_char(
tty,
- cy_readb(
+ readb(
base_addr +
(CyRDSR <<
index)),
@@ -1123,7 +1081,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
} else if (data & CyFRAME) {
tty_insert_flip_char(
tty,
- cy_readb(
+ readb(
base_addr +
(CyRDSR <<
index)),
@@ -1135,7 +1093,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
/* Pieces of seven... */
tty_insert_flip_char(
tty,
- cy_readb(
+ readb(
base_addr +
(CyRDSR <<
index)),
@@ -1154,7 +1112,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
*/
tty_insert_flip_char(
tty,
- cy_readb(
+ readb(
base_addr +
(CyRDSR <<
index)),
@@ -1186,7 +1144,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
}
} else { /* normal character reception */
/* load # chars available from the chip */
- char_count = cy_readb(base_addr +
+ char_count = readb(base_addr +
(CyRDCR << index));
#ifdef CY_ENABLE_MONITORING
@@ -1198,7 +1156,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
#endif
len = tty_buffer_request_room(tty, char_count);
while (len--) {
- data = cy_readb(base_addr +
+ data = readb(base_addr +
(CyRDSR << index));
tty_insert_flip_char(tty, data,
TTY_NORMAL);
@@ -1223,29 +1181,27 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
is empty, we know we can always stuff a dozen
characters. */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: xmit intr, chip %d\n\r", chip);
+ printk(KERN_DEBUG "cyy_interrupt: xmit intr, chip %d\n", chip);
#endif
/* determine the channel & change to that context */
spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr + (CyTIR << index));
+ save_xir = (u_char) readb(base_addr + (CyTIR << index));
channel = (u_short) (save_xir & CyIRChannel);
- i = channel + chip * 4 + cinfo->first_line;
- save_car = cy_readb(base_addr + (CyCAR << index));
+ save_car = readb(base_addr + (CyCAR << index));
cy_writeb(base_addr + (CyCAR << index), save_xir);
/* validate the port# (as configured and open) */
- if ((i < 0) || (NR_PORTS <= i)) {
+ if (channel + chip * 4 >= cinfo->nports) {
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) &
+ readb(base_addr + (CySRER << index)) &
~CyTxRdy);
goto txend;
}
- info = &cy_port[i];
- info->last_active = jiffies;
- if (info->tty == 0) {
+ info = &cinfo->ports[channel + chip * 4];
+ if (info->tty == NULL) {
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) &
+ readb(base_addr + (CySRER << index)) &
~CyTxRdy);
goto txdone;
}
@@ -1278,29 +1234,29 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
while (char_count-- > 0) {
if (!info->xmit_cnt) {
- if (cy_readb(base_addr + (CySRER << index)) &
+ if (readb(base_addr + (CySRER << index)) &
CyTxMpty) {
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr +
+ readb(base_addr +
(CySRER << index)) &
~CyTxMpty);
} else {
cy_writeb(base_addr + (CySRER << index),
- (cy_readb(base_addr +
+ (readb(base_addr +
(CySRER << index)) &
~CyTxRdy) | CyTxMpty);
}
goto txdone;
}
- if (info->xmit_buf == 0) {
+ if (info->xmit_buf == NULL) {
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index))&
+ readb(base_addr + (CySRER << index)) &
~CyTxRdy);
goto txdone;
}
if (info->tty->stopped || info->tty->hw_stopped) {
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index))&
+ readb(base_addr + (CySRER << index)) &
~CyTxRdy);
goto txdone;
}
@@ -1333,7 +1289,6 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip,
0);
info->icount.tx++;
char_count--;
- } else {
}
}
}
@@ -1353,19 +1308,16 @@ txend:
/* determine the channel & change to that context */
spin_lock(&cinfo->card_lock);
- save_xir = (u_char) cy_readb(base_addr + (CyMIR << index));
+ save_xir = (u_char) readb(base_addr + (CyMIR << index));
channel = (u_short) (save_xir & CyIRChannel);
- info = &cy_port[channel + chip * 4 + cinfo->first_line];
- info->last_active = jiffies;
- save_car = cy_readb(base_addr + (CyCAR << index));
+ info = &cinfo->ports[channel + chip * 4];
+ save_car = readb(base_addr + (CyCAR << index));
cy_writeb(base_addr + (CyCAR << index), save_xir);
- mdm_change = cy_readb(base_addr + (CyMISR << index));
- mdm_status = cy_readb(base_addr + (CyMSVR1 << index));
+ mdm_change = readb(base_addr + (CyMISR << index));
+ mdm_status = readb(base_addr + (CyMSVR1 << index));
- if (info->tty == 0) { /* no place for data, ignore it */
- ;
- } else {
+ if (info->tty) {
if (mdm_change & CyANY_DELTA) {
/* For statistics only */
if (mdm_change & CyDCD)
@@ -1398,7 +1350,7 @@ txend:
info->tty->hw_stopped = 0;
cy_writeb(base_addr +
(CySRER << index),
- cy_readb(base_addr +
+ readb(base_addr +
(CySRER <<
index))|
CyTxRdy);
@@ -1412,17 +1364,17 @@ txend:
info->tty->hw_stopped = 1;
cy_writeb(base_addr +
(CySRER << index),
- cy_readb(base_addr +
+ readb(base_addr +
(CySRER <<
index)) &
~CyTxRdy);
}
}
}
- if (mdm_change & CyDSR) {
+/* if (mdm_change & CyDSR) {
}
if (mdm_change & CyRI) {
- }
+ }*/
}
/* end of service */
cy_writeb(base_addr + (CyMIR << index), (save_xir & 0x3f));
@@ -1438,16 +1390,16 @@ txend:
static irqreturn_t cyy_interrupt(int irq, void *dev_id)
{
int status;
- struct cyclades_card *cinfo;
+ struct cyclades_card *cinfo = dev_id;
void __iomem *base_addr, *card_base_addr;
int chip;
int index;
int too_many;
int had_work;
- if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
+ if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyy_interrupt: spurious interrupt %d\n\r", irq);
+ printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
@@ -1455,6 +1407,10 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
card_base_addr = cinfo->base_addr;
index = cinfo->bus_index;
+ /* card was not initialized yet (e.g. DEBUG_SHIRQ) */
+ if (unlikely(card_base_addr == NULL))
+ return IRQ_HANDLED;
+
/* This loop checks all chips in the card. Make a note whenever
_any_ chip had some work to do, as this is considered an
indication that there will be more to do. Only when no chip
@@ -1466,7 +1422,7 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
base_addr = cinfo->base_addr +
(cy_chip_offset[chip] << index);
too_many = 0;
- while ((status = cy_readb(base_addr +
+ while ((status = readb(base_addr +
(CySVRR << index))) != 0x00) {
had_work++;
/* The purpose of the following test is to ensure that
@@ -1498,7 +1454,7 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id)
static int
cyz_fetch_msg(struct cyclades_card *cinfo,
- uclong * channel, ucchar * cmd, uclong * param)
+ __u32 * channel, __u8 * cmd, __u32 * param)
{
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
@@ -1509,16 +1465,15 @@ cyz_fetch_msg(struct cyclades_card *cinfo,
if (!ISZLOADED(*cinfo)) {
return -1;
}
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
- 0xfffff);
+ zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
- loc_doorbell = cy_readl(&((struct RUNTIME_9060 __iomem *)
+ loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *)
(cinfo->ctl_addr))->loc_doorbell);
if (loc_doorbell) {
*cmd = (char)(0xff & loc_doorbell);
- *channel = cy_readl(&board_ctrl->fwcmd_channel);
- *param = (uclong) cy_readl(&board_ctrl->fwcmd_param);
+ *channel = readl(&board_ctrl->fwcmd_channel);
+ *param = (__u32) readl(&board_ctrl->fwcmd_param);
cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
loc_doorbell, 0xffffffff);
return 1;
@@ -1528,28 +1483,27 @@ cyz_fetch_msg(struct cyclades_card *cinfo,
static int
cyz_issue_cmd(struct cyclades_card *cinfo,
- uclong channel, ucchar cmd, uclong param)
+ __u32 channel, __u8 cmd, __u32 param)
{
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
struct BOARD_CTRL __iomem *board_ctrl;
- unsigned long __iomem *pci_doorbell;
+ __u32 __iomem *pci_doorbell;
int index;
firm_id = cinfo->base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo)) {
return -1;
}
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
- 0xfffff);
+ zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
index = 0;
pci_doorbell =
&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
- while ((cy_readl(pci_doorbell) & 0xff) != 0) {
+ while ((readl(pci_doorbell) & 0xff) != 0) {
if (index++ == 1000) {
- return (int)(cy_readl(pci_doorbell) & 0xff);
+ return (int)(readl(pci_doorbell) & 0xff);
}
udelay(50L);
}
@@ -1561,34 +1515,30 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
} /* cyz_issue_cmd */
static void
-cyz_handle_rx(struct cyclades_port *info,
- volatile struct CH_CTRL __iomem * ch_ctrl,
- volatile struct BUF_CTRL __iomem * buf_ctrl)
+cyz_handle_rx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
+ struct BUF_CTRL __iomem *buf_ctrl)
{
- struct cyclades_card *cinfo = &cy_card[info->card];
+ struct cyclades_card *cinfo = info->card;
struct tty_struct *tty = info->tty;
- volatile int char_count;
+ int char_count;
int len;
#ifdef BLOCKMOVE
- int small_count;
+ unsigned char *buf;
#else
char data;
#endif
- volatile uclong rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
+ __u32 rx_put, rx_get, new_rx_get, rx_bufsize, rx_bufaddr;
- rx_get = new_rx_get = cy_readl(&buf_ctrl->rx_get);
- rx_put = cy_readl(&buf_ctrl->rx_put);
- rx_bufsize = cy_readl(&buf_ctrl->rx_bufsize);
- rx_bufaddr = cy_readl(&buf_ctrl->rx_bufaddr);
+ rx_get = new_rx_get = readl(&buf_ctrl->rx_get);
+ rx_put = readl(&buf_ctrl->rx_put);
+ rx_bufsize = readl(&buf_ctrl->rx_bufsize);
+ rx_bufaddr = readl(&buf_ctrl->rx_bufaddr);
if (rx_put >= rx_get)
char_count = rx_put - rx_get;
else
char_count = rx_put - rx_get + rx_bufsize;
if (char_count) {
- info->last_active = jiffies;
- info->jiffies[1] = jiffies;
-
#ifdef CY_ENABLE_MONITORING
info->mon.int_count++;
info->mon.char_count += char_count;
@@ -1596,7 +1546,7 @@ cyz_handle_rx(struct cyclades_port *info,
info->mon.char_max = char_count;
info->mon.char_last = char_count;
#endif
- if (tty == 0) {
+ if (tty == NULL) {
/* flush received characters */
new_rx_get = (new_rx_get + char_count) &
(rx_bufsize - 1);
@@ -1606,30 +1556,28 @@ cyz_handle_rx(struct cyclades_port *info,
/* we'd like to use memcpy(t, f, n) and memset(s, c, count)
for performance, but because of buffer boundaries, there
may be several steps to the operation */
- while (0 < (small_count = min_t(unsigned int,
- rx_bufsize - new_rx_get,
- min_t(unsigned int, TTY_FLIPBUF_SIZE -
- tty->flip.count, char_count)))){
- memcpy_fromio(tty->flip.char_buf_ptr,
- (char *)(cinfo->base_addr + rx_bufaddr +
- new_rx_get),
- small_count);
+ while (1) {
+ len = tty_prepare_flip_string(tty, &buf,
+ char_count);
+ if (!len)
+ break;
- tty->flip.char_buf_ptr += small_count;
- memset(tty->flip.flag_buf_ptr, TTY_NORMAL,
- small_count);
- tty->flip.flag_buf_ptr += small_count;
- new_rx_get = (new_rx_get + small_count) &
+ len = min_t(unsigned int, min(len, char_count),
+ rx_bufsize - new_rx_get);
+
+ memcpy_fromio(buf, cinfo->base_addr +
+ rx_bufaddr + new_rx_get, len);
+
+ new_rx_get = (new_rx_get + len) &
(rx_bufsize - 1);
- char_count -= small_count;
- info->icount.rx += small_count;
- info->idle_stats.recv_bytes += small_count;
- tty->flip.count += small_count;
+ char_count -= len;
+ info->icount.rx += len;
+ info->idle_stats.recv_bytes += len;
}
#else
len = tty_buffer_request_room(tty, char_count);
while (len--) {
- data = cy_readb(cinfo->base_addr + rx_bufaddr +
+ data = readb(cinfo->base_addr + rx_bufaddr +
new_rx_get);
new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1);
tty_insert_flip_char(tty, data, TTY_NORMAL);
@@ -1640,13 +1588,12 @@ cyz_handle_rx(struct cyclades_port *info,
#ifdef CONFIG_CYZ_INTR
/* Recalculate the number of chars in the RX buffer and issue
a cmd in case it's higher than the RX high water mark */
- rx_put = cy_readl(&buf_ctrl->rx_put);
+ rx_put = readl(&buf_ctrl->rx_put);
if (rx_put >= rx_get)
char_count = rx_put - rx_get;
else
char_count = rx_put - rx_get + rx_bufsize;
- if (char_count >= (int)cy_readl(&buf_ctrl->
- rx_threshold)) {
+ if (char_count >= (int)readl(&buf_ctrl->rx_threshold)) {
cy_sched_event(info, Cy_EVENT_Z_RX_FULL);
}
#endif
@@ -1659,26 +1606,25 @@ cyz_handle_rx(struct cyclades_port *info,
}
static void
-cyz_handle_tx(struct cyclades_port *info,
- volatile struct CH_CTRL __iomem * ch_ctrl,
- volatile struct BUF_CTRL __iomem * buf_ctrl)
+cyz_handle_tx(struct cyclades_port *info, struct CH_CTRL __iomem *ch_ctrl,
+ struct BUF_CTRL __iomem *buf_ctrl)
{
- struct cyclades_card *cinfo = &cy_card[info->card];
+ struct cyclades_card *cinfo = info->card;
struct tty_struct *tty = info->tty;
char data;
- volatile int char_count;
+ int char_count;
#ifdef BLOCKMOVE
int small_count;
#endif
- volatile uclong tx_put, tx_get, tx_bufsize, tx_bufaddr;
+ __u32 tx_put, tx_get, tx_bufsize, tx_bufaddr;
if (info->xmit_cnt <= 0) /* Nothing to transmit */
return;
- tx_get = cy_readl(&buf_ctrl->tx_get);
- tx_put = cy_readl(&buf_ctrl->tx_put);
- tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
- tx_bufaddr = cy_readl(&buf_ctrl->tx_bufaddr);
+ tx_get = readl(&buf_ctrl->tx_get);
+ tx_put = readl(&buf_ctrl->tx_put);
+ tx_bufsize = readl(&buf_ctrl->tx_bufsize);
+ tx_bufaddr = readl(&buf_ctrl->tx_bufaddr);
if (tx_put >= tx_get)
char_count = tx_get - tx_put - 1 + tx_bufsize;
else
@@ -1686,9 +1632,8 @@ cyz_handle_tx(struct cyclades_port *info,
if (char_count) {
- if (tty == 0) {
+ if (tty == NULL)
goto ztxdone;
- }
if (info->x_char) { /* send special char */
data = info->x_char;
@@ -1698,8 +1643,6 @@ cyz_handle_tx(struct cyclades_port *info,
info->x_char = 0;
char_count--;
info->icount.tx++;
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
}
#ifdef BLOCKMOVE
while (0 < (small_count = min_t(unsigned int,
@@ -1719,8 +1662,6 @@ cyz_handle_tx(struct cyclades_port *info,
info->xmit_cnt -= small_count;
info->xmit_tail = (info->xmit_tail + small_count) &
(SERIAL_XMIT_SIZE - 1);
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
}
#else
while (info->xmit_cnt && char_count) {
@@ -1733,8 +1674,6 @@ cyz_handle_tx(struct cyclades_port *info,
tx_put = (tx_put + 1) & (tx_bufsize - 1);
char_count--;
info->icount.tx++;
- info->last_active = jiffies;
- info->jiffies[2] = jiffies;
}
#endif
ztxdone:
@@ -1750,33 +1689,32 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
{
struct tty_struct *tty;
struct cyclades_port *info;
- static volatile struct FIRM_ID __iomem *firm_id;
- static volatile struct ZFW_CTRL __iomem *zfw_ctrl;
- static volatile struct BOARD_CTRL __iomem *board_ctrl;
- static volatile struct CH_CTRL __iomem *ch_ctrl;
- static volatile struct BUF_CTRL __iomem *buf_ctrl;
- uclong channel;
- ucchar cmd;
- uclong param;
- uclong hw_ver, fw_ver;
+ static struct FIRM_ID __iomem *firm_id;
+ static struct ZFW_CTRL __iomem *zfw_ctrl;
+ static struct BOARD_CTRL __iomem *board_ctrl;
+ static struct CH_CTRL __iomem *ch_ctrl;
+ static struct BUF_CTRL __iomem *buf_ctrl;
+ __u32 channel;
+ __u8 cmd;
+ __u32 param;
+ __u32 hw_ver, fw_ver;
int special_count;
int delta_count;
firm_id = cinfo->base_addr + ID_ADDRESS;
- zfw_ctrl = cinfo->base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
- 0xfffff);
+ zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
- fw_ver = cy_readl(&board_ctrl->fw_version);
- hw_ver = cy_readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
+ fw_ver = readl(&board_ctrl->fw_version);
+ hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
mail_box_0);
while (cyz_fetch_msg(cinfo, &channel, &cmd, &param) == 1) {
special_count = 0;
delta_count = 0;
- info = &cy_port[channel + cinfo->first_line];
- if ((tty = info->tty) == 0) {
+ info = &cinfo->ports[channel];
+ if ((tty = info->tty) == NULL)
continue;
- }
+
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
@@ -1801,7 +1739,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
delta_count++;
if (info->flags & ASYNC_CHECK_CD) {
if ((fw_ver > 241 ? ((u_long) param) :
- cy_readl(&ch_ctrl->rs_status)) &
+ readl(&ch_ctrl->rs_status)) &
C_RS_DCD) {
cy_sched_event(info,
Cy_EVENT_OPEN_WAKEUP);
@@ -1833,8 +1771,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
case C_CM_INTBACK2:
/* Reception Interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: rcvd intr, card %d, "
- "port %ld\n\r", info->card, channel);
+ printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "
+ "port %ld\n", info->card, channel);
#endif
cyz_handle_rx(info, ch_ctrl, buf_ctrl);
break;
@@ -1843,8 +1781,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
case C_CM_INTBACK:
/* Transmission Interrupt */
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: xmit intr, card %d, "
- "port %ld\n\r", info->card, channel);
+ printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "
+ "port %ld\n", info->card, channel);
#endif
cyz_handle_tx(info, ch_ctrl, buf_ctrl);
break;
@@ -1865,18 +1803,19 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
#ifdef CONFIG_CYZ_INTR
static irqreturn_t cyz_interrupt(int irq, void *dev_id)
{
- struct cyclades_card *cinfo;
+ struct cyclades_card *cinfo = dev_id;
- if ((cinfo = (struct cyclades_card *)dev_id) == 0) {
+ if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: spurious interrupt %d\n\r", irq);
+ printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
- if (!ISZLOADED(*cinfo)) {
+ if (unlikely(!ISZLOADED(*cinfo))) {
#ifdef CY_DEBUG_INTERRUPTS
- printk("cyz_interrupt: board not yet loaded (IRQ%d).\n\r", irq);
+ printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
+ "(IRQ%d).\n", irq);
#endif
return IRQ_NONE;
}
@@ -1890,19 +1829,18 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id)
static void cyz_rx_restart(unsigned long arg)
{
struct cyclades_port *info = (struct cyclades_port *)arg;
+ struct cyclades_card *card = info->card;
int retval;
- int card = info->card;
- uclong channel = (info->line) - (cy_card[card].first_line);
+ __u32 channel = info->line - card->first_line;
unsigned long flags;
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK2, 0L);
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);
if (retval != 0) {
- printk("cyc:cyz_rx_restart retval on ttyC%d was %x\n",
+ printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",
info->line, retval);
}
- cyz_rx_full_timer[info->line].function = NULL;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
#else /* CONFIG_CYZ_INTR */
@@ -1912,14 +1850,14 @@ static void cyz_poll(unsigned long arg)
struct cyclades_card *cinfo;
struct cyclades_port *info;
struct tty_struct *tty;
- static volatile struct FIRM_ID *firm_id;
- static volatile struct ZFW_CTRL *zfw_ctrl;
- static volatile struct BOARD_CTRL *board_ctrl;
- static volatile struct CH_CTRL *ch_ctrl;
- static volatile struct BUF_CTRL *buf_ctrl;
+ static struct FIRM_ID *firm_id;
+ static struct ZFW_CTRL *zfw_ctrl;
+ static struct BOARD_CTRL *board_ctrl;
+ static struct CH_CTRL *ch_ctrl;
+ static struct BUF_CTRL *buf_ctrl;
+ unsigned long expires = jiffies + HZ;
int card, port;
- cyz_timerlist.expires = jiffies + (HZ);
for (card = 0; card < NR_CARDS; card++) {
cinfo = &cy_card[card];
@@ -1930,12 +1868,12 @@ static void cyz_poll(unsigned long arg)
firm_id = cinfo->base_addr + ID_ADDRESS;
zfw_ctrl = cinfo->base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &(zfw_ctrl->board_ctrl);
/* Skip first polling cycle to avoid racing conditions with the FW */
if (!cinfo->intr_enabled) {
- cinfo->nports = (int)cy_readl(&board_ctrl->n_channel);
+ cinfo->nports = (int)readl(&board_ctrl->n_channel);
cinfo->intr_enabled = 1;
continue;
}
@@ -1943,7 +1881,7 @@ static void cyz_poll(unsigned long arg)
cyz_handle_cmd(cinfo);
for (port = 0; port < cinfo->nports; port++) {
- info = &cy_port[port + cinfo->first_line];
+ info = &cinfo->ports[port];
tty = info->tty;
ch_ctrl = &(zfw_ctrl->ch_ctrl[port]);
buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);
@@ -1953,9 +1891,9 @@ static void cyz_poll(unsigned long arg)
cyz_handle_tx(info, ch_ctrl, buf_ctrl);
}
/* poll every 'cyz_polling_cycle' period */
- cyz_timerlist.expires = jiffies + cyz_polling_cycle;
+ expires = jiffies + cyz_polling_cycle;
}
- add_timer(&cyz_timerlist);
+ mod_timer(&cyz_timerlist, expires);
} /* cyz_poll */
#endif /* CONFIG_CYZ_INTR */
@@ -1968,20 +1906,21 @@ static void cyz_poll(unsigned long arg)
*/
static int startup(struct cyclades_port *info)
{
+ struct cyclades_card *card;
unsigned long flags;
int retval = 0;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
unsigned long page;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ channel = info->line - card->first_line;
page = get_zeroed_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
@@ -2001,24 +1940,22 @@ static int startup(struct cyclades_port *info)
else
info->xmit_buf = (unsigned char *)page;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
set_line_char(info);
- if (!IS_CYC_Z(cy_card[card])) {
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr +
- (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
#ifdef CY_DEBUG_OPEN
- printk("cyc startup card %d, chip %d, channel %d, "
- "base_addr %lx\n",
- card, chip, channel, (long)base_addr);
- /**/
+ printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "
+ "base_addr %p\n",
+ card, chip, channel, base_addr);
#endif
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
@@ -2034,14 +1971,14 @@ static int startup(struct cyclades_port *info)
cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:startup raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:startup raising DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) | CyRxData);
+ readb(base_addr + (CySRER << index)) | CyRxData);
info->flags |= ASYNC_INITIALIZED;
if (info->tty) {
@@ -2054,7 +1991,7 @@ static int startup(struct cyclades_port *info)
info->idle_stats.recv_idle =
info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
struct FIRM_ID __iomem *firm_id;
@@ -2063,24 +2000,23 @@ static int startup(struct cyclades_port *info)
struct CH_CTRL __iomem *ch_ctrl;
int retval;
- base_addr = cy_card[card].base_addr;
+ base_addr = card->base_addr;
firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])) {
+ if (!ISZLOADED(*card)) {
return -ENODEV;
}
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
#ifdef CY_DEBUG_OPEN
- printk("cyc startup Z card %d, channel %d, base_addr %lx\n",
- card, channel, (long)base_addr);
- /**/
+ printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "
+ "base_addr %p\n", card, channel, base_addr);
#endif
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);
#ifdef Z_WAKE
@@ -2102,33 +2038,31 @@ static int startup(struct cyclades_port *info)
#endif /* CONFIG_CYZ_INTR */
#endif /* Z_WAKE */
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
if (retval != 0) {
- printk("cyc:startup(1) retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "
+ "%x\n", info->line, retval);
}
/* Flush RX buffers before raising DTR and RTS */
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_RX,
- 0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);
if (retval != 0) {
- printk("cyc:startup(2) retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "
+ "%x\n", info->line, retval);
}
/* set timeout !!! */
/* set RTS and DTR !!! */
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
+ readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |
C_RS_DTR);
- retval = cyz_issue_cmd(&cy_card[info->card], channel,
- C_CM_IOCTLM, 0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
if (retval != 0) {
- printk("cyc:startup(3) retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was "
+ "%x\n", info->line, retval);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:startup raising Z DTR\n");
+ printk(KERN_DEBUG "cyc:startup raising Z DTR\n");
#endif
/* enable send, recv, modem !!! */
@@ -2144,51 +2078,50 @@ static int startup(struct cyclades_port *info)
info->idle_stats.recv_idle =
info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
#ifdef CY_DEBUG_OPEN
- printk(" cyc startup done\n");
+ printk(KERN_DEBUG "cyc startup done\n");
#endif
return 0;
errout:
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
return retval;
} /* startup */
static void start_xmit(struct cyclades_port *info)
{
+ struct cyclades_card *card;
unsigned long flags;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr +
- (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index), channel);
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
- CY_UNLOCK(info, flags);
+ readb(base_addr + (CySRER << index)) | CyTxRdy);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
#ifdef CONFIG_CYZ_INTR
int retval;
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_INTBACK,
- 0L);
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);
if (retval != 0) {
- printk("cyc:start_xmit retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "
+ "%x\n", info->line, retval);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
#else /* CONFIG_CYZ_INTR */
/* Don't have to do anything at this time */
#endif /* CONFIG_CYZ_INTR */
@@ -2201,30 +2134,30 @@ static void start_xmit(struct cyclades_port *info)
*/
static void shutdown(struct cyclades_port *info)
{
+ struct cyclades_card *card;
unsigned long flags;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
if (!(info->flags & ASYNC_INITIALIZED)) {
return;
}
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr +
- (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
#ifdef CY_DEBUG_OPEN
- printk("cyc shutdown Y card %d, chip %d, channel %d, "
- "base_addr %lx\n",
- card, chip, channel, (long)base_addr);
+ printk(KERN_DEBUG "cyc shutdown Y card %d, chip %d, "
+ "channel %d, base_addr %p\n",
+ card, chip, channel, base_addr);
#endif
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
/* Clear delta_msr_wait queue to avoid mem leaks. */
wake_up_interruptible(&info->delta_msr_wait);
@@ -2240,10 +2173,10 @@ static void shutdown(struct cyclades_port *info)
cy_writeb(base_addr + (CyMSVR1 << index), ~CyRTS);
cy_writeb(base_addr + (CyMSVR2 << index), ~CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc shutdown dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc shutdown dropping DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
}
cyy_issue_cmd(base_addr, CyCHAN_CTL | CyDIS_RCVR, index);
@@ -2254,7 +2187,7 @@ static void shutdown(struct cyclades_port *info)
set_bit(TTY_IO_ERROR, &info->tty->flags);
}
info->flags &= ~ASYNC_INITIALIZED;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
@@ -2262,23 +2195,23 @@ static void shutdown(struct cyclades_port *info)
struct CH_CTRL __iomem *ch_ctrl;
int retval;
- base_addr = cy_card[card].base_addr;
+ base_addr = card->base_addr;
#ifdef CY_DEBUG_OPEN
- printk("cyc shutdown Z card %d, channel %d, base_addr %lx\n",
- card, channel, (long)base_addr);
+ printk(KERN_DEBUG "cyc shutdown Z card %d, channel %d, "
+ "base_addr %p\n", card, channel, base_addr);
#endif
firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])) {
+ if (!ISZLOADED(*card)) {
return;
}
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
if (info->xmit_buf) {
unsigned char *temp;
@@ -2289,16 +2222,16 @@ static void shutdown(struct cyclades_port *info)
if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
cy_writel(&ch_ctrl[channel].rs_control,
- (uclong)(cy_readl(&ch_ctrl[channel].rs_control)&
+ (__u32)(readl(&ch_ctrl[channel].rs_control) &
~(C_RS_RTS | C_RS_DTR)));
- retval = cyz_issue_cmd(&cy_card[info->card], channel,
+ retval = cyz_issue_cmd(info->card, channel,
C_CM_IOCTLM, 0L);
if (retval != 0) {
- printk("cyc:shutdown retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR"cyc:shutdown retval on ttyC%d "
+ "was %x\n", info->line, retval);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:shutdown dropping Z DTR\n");
+ printk(KERN_DEBUG "cyc:shutdown dropping Z DTR\n");
#endif
}
@@ -2307,11 +2240,11 @@ static void shutdown(struct cyclades_port *info)
}
info->flags &= ~ASYNC_INITIALIZED;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
#ifdef CY_DEBUG_OPEN
- printk(" cyc shutdown done\n");
+ printk(KERN_DEBUG "cyc shutdown done\n");
#endif
} /* shutdown */
@@ -2332,7 +2265,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
int retval;
void __iomem *base_addr;
- cinfo = &cy_card[info->card];
+ cinfo = info->card;
channel = info->line - cinfo->first_line;
/*
@@ -2340,9 +2273,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
* until it's done, and then try again.
*/
if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
- }
+ wait_event_interruptible(info->close_wait,
+ !(info->flags & ASYNC_CLOSING));
return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
}
@@ -2365,17 +2297,16 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
retval = 0;
add_wait_queue(&info->open_wait, &wait);
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready before block: ttyC%d, count = %d\n",
- info->line, info->count);
- /**/
+ printk(KERN_DEBUG "cyc block_til_ready before block: ttyC%d, "
+ "count = %d\n", info->line, info->count);
#endif
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&cinfo->card_lock, flags);
if (!tty_hung_up_p(filp))
info->count--;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
#ifdef CY_DEBUG_COUNT
- printk("cyc block_til_ready: (%d): decrementing count to %d\n",
- current->pid, info->count);
+ printk(KERN_DEBUG "cyc block_til_ready: (%d): decrementing count to "
+ "%d\n", current->pid, info->count);
#endif
info->blocked_open++;
@@ -2386,7 +2317,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
while (1) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&cinfo->card_lock, flags);
if ((tty->termios->c_cflag & CBAUD)) {
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
@@ -2395,15 +2326,14 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
cy_writeb(base_addr + (CyMSVR2 << index),
CyDTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:block_til_ready raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr +
- (CyMSVR1 << index)),
- cy_readb(base_addr +
- (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:block_til_ready raising "
+ "DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
@@ -2413,26 +2343,25 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
break;
}
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&cinfo->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
- (cy_readb(base_addr +
+ (readb(base_addr +
(CyMSVR1 << index)) & CyDCD))) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
break;
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready blocking: ttyC%d, "
- "count = %d\n",
- info->line, info->count);
- /**/
+ printk(KERN_DEBUG "cyc block_til_ready blocking: "
+ "ttyC%d, count = %d\n",
+ info->line, info->count);
#endif
schedule();
}
@@ -2446,31 +2375,30 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
base_addr = cinfo->base_addr;
firm_id = base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo)) {
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
return -EINVAL;
}
- zfw_ctrl = base_addr + (cy_readl(&firm_id->zfwctrl_addr) &
- 0xfffff);
+ zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)& 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
while (1) {
if ((tty->termios->c_cflag & CBAUD)) {
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].
- rs_control) | (C_RS_RTS |
- C_RS_DTR));
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
+ readl(&ch_ctrl[channel].rs_control) |
+ C_RS_RTS | C_RS_DTR);
+ retval = cyz_issue_cmd(cinfo,
+ channel, C_CM_IOCTLM, 0L);
if (retval != 0) {
- printk("cyc:block_til_ready retval on "
- "ttyC%d was %x\n",
+ printk(KERN_ERR "cyc:block_til_ready "
+ "retval on ttyC%d was %x\n",
info->line, retval);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:block_til_ready raising Z DTR\n");
+ printk(KERN_DEBUG "cyc:block_til_ready raising "
+ "Z DTR\n");
#endif
}
@@ -2482,7 +2410,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
break;
}
if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) ||
- (cy_readl(&ch_ctrl[channel].rs_status) &
+ (readl(&ch_ctrl[channel].rs_status) &
C_RS_DCD))) {
break;
}
@@ -2491,28 +2419,26 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
break;
}
#ifdef CY_DEBUG_OPEN
- printk("cyc block_til_ready blocking: ttyC%d, "
- "count = %d\n",
- info->line, info->count);
- /**/
+ printk(KERN_DEBUG "cyc block_til_ready blocking: "
+ "ttyC%d, count = %d\n",
+ info->line, info->count);
#endif
schedule();
}
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
if (!tty_hung_up_p(filp)) {
info->count++;
#ifdef CY_DEBUG_COUNT
- printk("cyc:block_til_ready (%d): incrementing count to %d\n",
- current->pid, info->count);
+ printk(KERN_DEBUG "cyc:block_til_ready (%d): incrementing "
+ "count to %d\n", current->pid, info->count);
#endif
}
info->blocked_open--;
#ifdef CY_DEBUG_OPEN
- printk("cyc:block_til_ready after blocking: ttyC%d, count = %d\n",
- info->line, info->count);
- /**/
+ printk(KERN_DEBUG "cyc:block_til_ready after blocking: ttyC%d, "
+ "count = %d\n", info->line, info->count);
#endif
if (retval)
return retval;
@@ -2527,13 +2453,20 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
static int cy_open(struct tty_struct *tty, struct file *filp)
{
struct cyclades_port *info;
+ unsigned int i;
int retval, line;
line = tty->index;
if ((line < 0) || (NR_PORTS <= line)) {
return -ENODEV;
}
- info = &cy_port[line];
+ for (i = 0; i < NR_CARDS; i++)
+ if (line < cy_card[i].first_line + cy_card[i].nports &&
+ line >= cy_card[i].first_line)
+ break;
+ if (i >= NR_CARDS)
+ return -ENODEV;
+ info = &cy_card[i].ports[line - cy_card[i].first_line];
if (info->line < 0) {
return -ENODEV;
}
@@ -2542,23 +2475,23 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
treat it as absent from the system. This
will make the user pay attention.
*/
- if (IS_CYC_Z(cy_card[info->card])) {
- struct cyclades_card *cinfo = &cy_card[info->card];
+ if (IS_CYC_Z(*info->card)) {
+ struct cyclades_card *cinfo = info->card;
struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
if (!ISZLOADED(*cinfo)) {
- if (((ZE_V1 == cy_readl(
- &((struct RUNTIME_9060 __iomem *)
+ if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *)
(cinfo->ctl_addr))->mail_box_0)) &&
Z_FPGA_CHECK(*cinfo)) &&
- (ZFIRM_HLT == cy_readl(
+ (ZFIRM_HLT == readl(
&firm_id->signature))) {
- printk("cyc:Cyclades-Z Error: you need an "
- "external power supply for this number "
- "of ports.\n\rFirmware halted.\r\n");
+ printk(KERN_ERR "cyc:Cyclades-Z Error: you "
+ "need an external power supply for "
+ "this number of ports.\nFirmware "
+ "halted.\n");
} else {
- printk("cyc:Cyclades-Z firmware not yet "
- "loaded\n");
+ printk(KERN_ERR "cyc:Cyclades-Z firmware not "
+ "yet loaded\n");
}
return -ENODEV;
}
@@ -2572,24 +2505,23 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
struct BOARD_CTRL __iomem *board_ctrl;
zfw_ctrl = cinfo->base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) &
- 0xfffff);
+ (readl(&firm_id->zfwctrl_addr) &
+ 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
/* Enable interrupts on the PLX chip */
cy_writew(cinfo->ctl_addr + 0x68,
- cy_readw(cinfo->ctl_addr +
- 0x68) | 0x0900);
+ readw(cinfo->ctl_addr + 0x68) | 0x0900);
/* Enable interrupts on the FW */
retval = cyz_issue_cmd(cinfo, 0,
C_CM_IRQ_ENBL, 0L);
if (retval != 0) {
- printk("cyc:IRQ enable retval was %x\n",
- retval);
+ printk(KERN_ERR "cyc:IRQ enable retval "
+ "was %x\n", retval);
}
cinfo->nports =
- (int)cy_readl(&board_ctrl->n_channel);
+ (int)readl(&board_ctrl->n_channel);
cinfo->intr_enabled = 1;
}
}
@@ -2599,7 +2531,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
}
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_open ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_open ttyC%d\n", info->line);
#endif
tty->driver_data = info;
info->tty = tty;
@@ -2607,12 +2539,12 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
}
#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_open ttyC%d, count = %d\n", info->line, info->count);
- /**/
+ printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
+ info->count);
#endif
info->count++;
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_open (%d): incrementing count to %d\n",
+ printk(KERN_DEBUG "cyc:cy_open (%d): incrementing count to %d\n",
current->pid, info->count);
#endif
@@ -2620,8 +2552,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
* If the port is the middle of closing, bail out now
*/
if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) {
- if (info->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&info->close_wait);
+ wait_event_interruptible(info->close_wait,
+ !(info->flags & ASYNC_CLOSING));
return (info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
}
@@ -2636,8 +2568,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
retval = block_til_ready(tty, filp, info);
if (retval) {
#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_open returning after block_til_ready with %d\n",
- retval);
+ printk(KERN_DEBUG "cyc:cy_open returning after block_til_ready "
+ "with %d\n", retval);
#endif
return retval;
}
@@ -2645,8 +2577,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
info->throttle = 0;
#ifdef CY_DEBUG_OPEN
- printk(" cyc:cy_open done\n");
- /**/
+ printk(KERN_DEBUG "cyc:cy_open done\n");
#endif
return 0;
} /* cy_open */
@@ -2656,9 +2587,10 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
*/
static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_card *card;
+ struct cyclades_port *info = tty->driver_data;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
unsigned long orig_jiffies;
int char_time;
@@ -2697,20 +2629,19 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
if (!timeout || timeout > 2 * info->timeout)
timeout = 2 * info->timeout;
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("In cy_wait_until_sent(%d) check=%lu...", timeout, char_time);
- printk("jiff=%lu...", jiffies);
+ printk(KERN_DEBUG "In cy_wait_until_sent(%d) check=%d, jiff=%lu...",
+ timeout, char_time, jiffies);
#endif
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = (info->line) - (card->first_line);
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
- while (cy_readb(base_addr + (CySRER << index)) & CyTxRdy) {
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
+ while (readb(base_addr + (CySRER << index)) & CyTxRdy) {
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("Not clean (jiff=%lu)...", jiffies);
+ printk(KERN_DEBUG "Not clean (jiff=%lu)...", jiffies);
#endif
if (msleep_interruptible(jiffies_to_msecs(char_time)))
break;
@@ -2718,13 +2649,11 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
timeout))
break;
}
- } else {
- /* Nothing to do! */
}
/* Run one more char cycle */
msleep_interruptible(jiffies_to_msecs(char_time * 5));
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
- printk("Clean (jiff=%lu)...done\n", jiffies);
+ printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
#endif
}
@@ -2733,25 +2662,29 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
*/
static void cy_close(struct tty_struct *tty, struct file *filp)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_close ttyC%d\n", info->line);
+ printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line);
#endif
if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
return;
}
- CY_LOCK(info, flags);
+ card = info->card;
+
+ spin_lock_irqsave(&card->card_lock, flags);
/* If the TTY is being hung up, nothing to do */
if (tty_hung_up_p(filp)) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
return;
}
#ifdef CY_DEBUG_OPEN
- printk("cyc:cy_close ttyC%d, count = %d\n", info->line, info->count);
+ printk(KERN_DEBUG "cyc:cy_close ttyC%d, count = %d\n", info->line,
+ info->count);
#endif
if ((tty->count == 1) && (info->count != 1)) {
/*
@@ -2761,22 +2694,22 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
- printk("cyc:cy_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
+ printk(KERN_ERR "cyc:cy_close: bad serial port count; "
+ "tty->count is 1, info->count is %d\n", info->count);
info->count = 1;
}
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_close at (%d): decrementing count to %d\n",
+ printk(KERN_DEBUG "cyc:cy_close at (%d): decrementing count to %d\n",
current->pid, info->count - 1);
#endif
if (--info->count < 0) {
#ifdef CY_DEBUG_COUNT
- printk("cyc:cyc_close setting count to 0\n");
+ printk(KERN_DEBUG "cyc:cyc_close setting count to 0\n");
#endif
info->count = 0;
}
if (info->count) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
return;
}
info->flags |= ASYNC_CLOSING;
@@ -2786,81 +2719,80 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
tty_wait_until_sent(tty, info->closing_wait);
}
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
- if (!IS_CYC_Z(cy_card[info->card])) {
- int channel = info->line - cy_card[info->card].first_line;
- int index = cy_card[info->card].bus_index;
- void __iomem *base_addr = cy_card[info->card].base_addr +
+ if (!IS_CYC_Z(*card)) {
+ int channel = info->line - card->first_line;
+ int index = card->bus_index;
+ void __iomem *base_addr = card->base_addr +
(cy_chip_offset[channel >> 2] << index);
/* Stop accepting input */
channel &= 0x03;
cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) & ~CyRxData);
+ readb(base_addr + (CySRER << index)) & ~CyRxData);
if (info->flags & ASYNC_INITIALIZED) {
/* Waiting for on-board buffers to be empty before closing
the port */
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
cy_wait_until_sent(tty, info->timeout);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
}
} else {
#ifdef Z_WAKE
/* Waiting for on-board buffers to be empty before closing the port */
- void __iomem *base_addr = cy_card[info->card].base_addr;
+ void __iomem *base_addr = card->base_addr;
struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
struct ZFW_CTRL __iomem *zfw_ctrl =
- base_addr + (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
struct CH_CTRL __iomem *ch_ctrl = zfw_ctrl->ch_ctrl;
- int channel = info->line - cy_card[info->card].first_line;
+ int channel = info->line - card->first_line;
int retval;
- if (cy_readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
- retval = cyz_issue_cmd(&cy_card[info->card], channel,
- C_CM_IOCTLW, 0L);
+ if (readl(&ch_ctrl[channel].flow_status) != C_FS_TXIDLE) {
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLW, 0L);
if (retval != 0) {
- printk("cyc:cy_close retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_DEBUG "cyc:cy_close retval on "
+ "ttyC%d was %x\n", info->line, retval);
}
- CY_UNLOCK(info, flags);
- interruptible_sleep_on(&info->shutdown_wait);
- CY_LOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
+ wait_for_completion_interruptible(&info->shutdown_wait);
+ spin_lock_irqsave(&card->card_lock, flags);
}
#endif
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
shutdown(info);
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
tty->closing = 0;
info->event = 0;
info->tty = NULL;
if (info->blocked_open) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
if (info->close_delay) {
msleep_interruptible(jiffies_to_msecs
(info->close_delay));
}
wake_up_interruptible(&info->open_wait);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
wake_up_interruptible(&info->close_wait);
#ifdef CY_DEBUG_OTHER
- printk(" cyc:cy_close done\n");
+ printk(KERN_DEBUG "cyc:cy_close done\n");
#endif
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} /* cy_close */
/* This routine gets called when tty_write has put something into
@@ -2878,12 +2810,12 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
*/
static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
unsigned long flags;
int c, ret = 0;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_write ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_write")) {
@@ -2893,7 +2825,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
if (!info->xmit_buf)
return 0;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&info->card->card_lock, flags);
while (1) {
c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
(int)(SERIAL_XMIT_SIZE - info->xmit_head)));
@@ -2909,7 +2841,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
count -= c;
ret += c;
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
info->idle_stats.xmit_bytes += ret;
info->idle_stats.xmit_idle = jiffies;
@@ -2929,11 +2861,11 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count)
*/
static void cy_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
unsigned long flags;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_put_char ttyC%d\n", info->line);
+ printk(KERN_DEBUG "cyc:cy_put_char ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
@@ -2942,9 +2874,9 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
if (!info->xmit_buf)
return;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&info->card->card_lock, flags);
if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
return;
}
@@ -2953,7 +2885,7 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
info->xmit_cnt++;
info->idle_stats.xmit_bytes++;
info->idle_stats.xmit_idle = jiffies;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
} /* cy_put_char */
/*
@@ -2962,10 +2894,10 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch)
*/
static void cy_flush_chars(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_flush_chars ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_flush_chars ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_flush_chars"))
@@ -2986,11 +2918,11 @@ static void cy_flush_chars(struct tty_struct *tty)
*/
static int cy_write_room(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
int ret;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_write_room ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_write_room ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_write_room"))
@@ -3003,46 +2935,49 @@ static int cy_write_room(struct tty_struct *tty)
static int cy_chars_in_buffer(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, channel;
+ struct cyclades_card *card;
+ struct cyclades_port *info = tty->driver_data;
+ int channel;
if (serial_paranoia_check(info, tty->name, "cy_chars_in_buffer"))
return 0;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ channel = (info->line) - (card->first_line);
#ifdef Z_EXT_CHARS_IN_BUFFER
if (!IS_CYC_Z(cy_card[card])) {
#endif /* Z_EXT_CHARS_IN_BUFFER */
#ifdef CY_DEBUG_IO
- printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt); /* */
+ printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
+ info->line, info->xmit_cnt);
#endif
return info->xmit_cnt;
#ifdef Z_EXT_CHARS_IN_BUFFER
} else {
- static volatile struct FIRM_ID *firm_id;
- static volatile struct ZFW_CTRL *zfw_ctrl;
- static volatile struct CH_CTRL *ch_ctrl;
- static volatile struct BUF_CTRL *buf_ctrl;
+ static struct FIRM_ID *firm_id;
+ static struct ZFW_CTRL *zfw_ctrl;
+ static struct CH_CTRL *ch_ctrl;
+ static struct BUF_CTRL *buf_ctrl;
int char_count;
- volatile uclong tx_put, tx_get, tx_bufsize;
+ __u32 tx_put, tx_get, tx_bufsize;
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ firm_id = card->base_addr + ID_ADDRESS;
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);
- tx_get = cy_readl(&buf_ctrl->tx_get);
- tx_put = cy_readl(&buf_ctrl->tx_put);
- tx_bufsize = cy_readl(&buf_ctrl->tx_bufsize);
+ tx_get = readl(&buf_ctrl->tx_get);
+ tx_put = readl(&buf_ctrl->tx_put);
+ tx_bufsize = readl(&buf_ctrl->tx_bufsize);
if (tx_put >= tx_get)
char_count = tx_put - tx_get;
else
char_count = tx_put - tx_get + tx_bufsize;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count); /* */
+ printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
+ info->line, info->xmit_cnt + char_count);
#endif
return info->xmit_cnt + char_count;
}
@@ -3055,10 +2990,10 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
* ------------------------------------------------------------
*/
-static void cyy_baud_calc(struct cyclades_port *info, uclong baud)
+static void cyy_baud_calc(struct cyclades_port *info, __u32 baud)
{
int co, co_val, bpr;
- uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
+ __u32 cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 :
25000000);
if (baud == 0) {
@@ -3086,9 +3021,10 @@ static void cyy_baud_calc(struct cyclades_port *info, uclong baud)
*/
static void set_line_char(struct cyclades_port *info)
{
+ struct cyclades_card *card;
unsigned long flags;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
unsigned cflag, iflag;
unsigned short chip_number;
int baud, baud_rate = 0;
@@ -3118,12 +3054,12 @@ static void set_line_char(struct cyclades_port *info)
}
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ channel = info->line - card->first_line;
chip_number = channel / 4;
- if (!IS_CYC_Z(cy_card[card])) {
+ if (!IS_CYC_Z(*card)) {
- index = cy_card[card].bus_index;
+ index = card->bus_index;
/* baud rate */
baud = tty_get_baud_rate(info->tty);
@@ -3241,10 +3177,9 @@ static void set_line_char(struct cyclades_port *info)
chip = channel >> 2;
channel &= 0x03;
- base_addr = cy_card[card].base_addr +
- (cy_chip_offset[chip] << index);
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
/* tx and rx baud rate */
@@ -3276,8 +3211,7 @@ static void set_line_char(struct cyclades_port *info)
if (C_CLOCAL(info->tty)) {
/* without modem intr */
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr +
- (CySRER << index)) | CyMdmCh);
+ readb(base_addr + (CySRER << index)) | CyMdmCh);
/* act on 1->0 modem transitions */
if ((cflag & CRTSCTS) && info->rflow) {
cy_writeb(base_addr + (CyMCOR1 << index),
@@ -3291,7 +3225,7 @@ static void set_line_char(struct cyclades_port *info)
} else {
/* without modem intr */
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr +
+ readb(base_addr +
(CySRER << index)) | CyMdmCh);
/* act on 1->0 modem transitions */
if ((cflag & CRTSCTS) && info->rflow) {
@@ -3316,10 +3250,10 @@ static void set_line_char(struct cyclades_port *info)
~CyDTR);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_line_char dropping DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
} else {
if (info->rtsdtr_inv) {
@@ -3330,17 +3264,17 @@ static void set_line_char(struct cyclades_port *info)
CyDTR);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_line_char raising DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
}
if (info->tty) {
clear_bit(TTY_IO_ERROR, &info->tty->flags);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
struct FIRM_ID __iomem *firm_id;
@@ -3348,16 +3282,16 @@ static void set_line_char(struct cyclades_port *info)
struct BOARD_CTRL __iomem *board_ctrl;
struct CH_CTRL __iomem *ch_ctrl;
struct BUF_CTRL __iomem *buf_ctrl;
- uclong sw_flow;
+ __u32 sw_flow;
int retval;
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (!ISZLOADED(cy_card[card])) {
+ firm_id = card->base_addr + ID_ADDRESS;
+ if (!ISZLOADED(*card)) {
return;
}
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
@@ -3408,10 +3342,10 @@ static void set_line_char(struct cyclades_port *info)
}
if (cflag & CSTOPB) {
cy_writel(&ch_ctrl->comm_data_l,
- cy_readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
+ readl(&ch_ctrl->comm_data_l) | C_DL_2STOP);
} else {
cy_writel(&ch_ctrl->comm_data_l,
- cy_readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
+ readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
}
if (cflag & PARENB) {
if (cflag & PARODD) {
@@ -3426,12 +3360,10 @@ static void set_line_char(struct cyclades_port *info)
/* CTS flow control flag */
if (cflag & CRTSCTS) {
cy_writel(&ch_ctrl->hw_flow,
- cy_readl(&ch_ctrl->
- hw_flow) | C_RS_CTS | C_RS_RTS);
+ readl(&ch_ctrl->hw_flow) | C_RS_CTS | C_RS_RTS);
} else {
- cy_writel(&ch_ctrl->hw_flow,
- cy_readl(&ch_ctrl->
- hw_flow) & ~(C_RS_CTS | C_RS_RTS));
+ cy_writel(&ch_ctrl->hw_flow, readl(&ch_ctrl->hw_flow) &
+ ~(C_RS_CTS | C_RS_RTS));
}
/* As the HW flow control is done in firmware, the driver
doesn't need to care about it */
@@ -3446,10 +3378,10 @@ static void set_line_char(struct cyclades_port *info)
}
cy_writel(&ch_ctrl->sw_flow, sw_flow);
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTL, 0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);
if (retval != 0) {
- printk("cyc:set_line_char retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:set_line_char retval on ttyC%d "
+ "was %x\n", info->line, retval);
}
/* CD sensitivity */
@@ -3461,22 +3393,22 @@ static void set_line_char(struct cyclades_port *info)
if (baud == 0) { /* baud rate is zero, turn off line */
cy_writel(&ch_ctrl->rs_control,
- cy_readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
+ readl(&ch_ctrl->rs_control) & ~C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char dropping Z DTR\n");
+ printk(KERN_DEBUG "cyc:set_line_char dropping Z DTR\n");
#endif
} else {
cy_writel(&ch_ctrl->rs_control,
- cy_readl(&ch_ctrl->rs_control) | C_RS_DTR);
+ readl(&ch_ctrl->rs_control) | C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_line_char raising Z DTR\n");
+ printk(KERN_DEBUG "cyc:set_line_char raising Z DTR\n");
#endif
}
- retval = cyz_issue_cmd(&cy_card[card], channel, C_CM_IOCTLM,0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM,0L);
if (retval != 0) {
- printk("cyc:set_line_char(2) retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
+ "was %x\n", info->line, retval);
}
if (info->tty) {
@@ -3490,14 +3422,15 @@ get_serial_info(struct cyclades_port *info,
struct serial_struct __user * retinfo)
{
struct serial_struct tmp;
- struct cyclades_card *cinfo = &cy_card[info->card];
+ struct cyclades_card *cinfo = info->card;
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tmp.type = info->type;
tmp.line = info->line;
- tmp.port = info->card * 0x100 + info->line - cinfo->first_line;
+ tmp.port = (info->card - cy_card) * 0x100 + info->line -
+ cinfo->first_line;
tmp.irq = cinfo->irq;
tmp.flags = info->flags;
tmp.close_delay = info->close_delay;
@@ -3566,25 +3499,25 @@ check_and_exit:
*/
static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
{
- int card, chip, channel, index;
+ struct cyclades_card *card;
+ int chip, channel, index;
unsigned char status;
unsigned int result;
unsigned long flags;
void __iomem *base_addr;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = (info->line) - (card->first_line);
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
- status = cy_readb(base_addr + (CySRER << index)) &
+ spin_lock_irqsave(&card->card_lock, flags);
+ status = readb(base_addr + (CySRER << index)) &
(CyTxRdy | CyTxMpty);
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
result = (status ? 0 : TIOCSER_TEMT);
} else {
/* Not supported yet */
@@ -3595,8 +3528,9 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
static int cy_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, chip, channel, index;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int chip, channel, index;
void __iomem *base_addr;
unsigned long flags;
unsigned char status;
@@ -3611,19 +3545,18 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
return -ENODEV;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
- status = cy_readb(base_addr + (CyMSVR1 << index));
- status |= cy_readb(base_addr + (CyMSVR2 << index));
- CY_UNLOCK(info, flags);
+ status = readb(base_addr + (CyMSVR1 << index));
+ status |= readb(base_addr + (CyMSVR2 << index));
+ spin_unlock_irqrestore(&card->card_lock, flags);
if (info->rtsdtr_inv) {
result = ((status & CyRTS) ? TIOCM_DTR : 0) |
@@ -3637,19 +3570,14 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
((status & CyDSR) ? TIOCM_DSR : 0) |
((status & CyCTS) ? TIOCM_CTS : 0);
} else {
- base_addr = cy_card[card].base_addr;
-
- if (cy_card[card].num_chips != -1) {
- return -EINVAL;
- }
-
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (ISZLOADED(cy_card[card])) {
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ base_addr = card->base_addr;
+ firm_id = card->base_addr + ID_ADDRESS;
+ if (ISZLOADED(*card)) {
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
- lstatus = cy_readl(&ch_ctrl[channel].rs_status);
+ lstatus = readl(&ch_ctrl[channel].rs_status);
result = ((lstatus & C_RS_RTS) ? TIOCM_RTS : 0) |
((lstatus & C_RS_DTR) ? TIOCM_DTR : 0) |
((lstatus & C_RS_DCD) ? TIOCM_CAR : 0) |
@@ -3669,8 +3597,9 @@ static int
cy_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, chip, channel, index;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int chip, channel, index;
void __iomem *base_addr;
unsigned long flags;
struct FIRM_ID __iomem *firm_id;
@@ -3683,16 +3612,15 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
return -ENODEV;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = (info->line) - (card->first_line);
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
if (set & TIOCM_RTS) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -3702,10 +3630,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
cy_writeb(base_addr + (CyMSVR1 << index),
CyRTS);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (clear & TIOCM_RTS) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -3715,10 +3643,10 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
cy_writeb(base_addr + (CyMSVR1 << index),
~CyRTS);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (set & TIOCM_DTR) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -3729,15 +3657,15 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
CyDTR);
}
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info raising DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_modem_info raising DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (clear & TIOCM_DTR) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -3749,68 +3677,69 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
}
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info dropping DTR\n");
- printk(" status: 0x%x, 0x%x\n",
- cy_readb(base_addr + (CyMSVR1 << index)),
- cy_readb(base_addr + (CyMSVR2 << index)));
+ printk(KERN_DEBUG "cyc:set_modem_info dropping DTR\n");
+ printk(KERN_DEBUG " status: 0x%x, 0x%x\n",
+ readb(base_addr + (CyMSVR1 << index)),
+ readb(base_addr + (CyMSVR2 << index)));
#endif
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
} else {
- base_addr = cy_card[card].base_addr;
+ base_addr = card->base_addr;
- firm_id = cy_card[card].base_addr + ID_ADDRESS;
- if (ISZLOADED(cy_card[card])) {
- zfw_ctrl = cy_card[card].base_addr +
- (cy_readl(&firm_id->zfwctrl_addr) & 0xfffff);
+ firm_id = card->base_addr + ID_ADDRESS;
+ if (ISZLOADED(*card)) {
+ zfw_ctrl = card->base_addr +
+ (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
if (set & TIOCM_RTS) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].
- rs_control) | C_RS_RTS);
- CY_UNLOCK(info, flags);
+ readl(&ch_ctrl[channel].rs_control) |
+ C_RS_RTS);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (clear & TIOCM_RTS) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].
- rs_control) & ~C_RS_RTS);
- CY_UNLOCK(info, flags);
+ readl(&ch_ctrl[channel].rs_control) &
+ ~C_RS_RTS);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (set & TIOCM_DTR) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].
- rs_control) | C_RS_DTR);
+ readl(&ch_ctrl[channel].rs_control) |
+ C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info raising Z DTR\n");
+ printk(KERN_DEBUG "cyc:set_modem_info raising "
+ "Z DTR\n");
#endif
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
if (clear & TIOCM_DTR) {
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writel(&ch_ctrl[channel].rs_control,
- cy_readl(&ch_ctrl[channel].
- rs_control) & ~C_RS_DTR);
+ readl(&ch_ctrl[channel].rs_control) &
+ ~C_RS_DTR);
#ifdef CY_DEBUG_DTR
- printk("cyc:set_modem_info clearing Z DTR\n");
+ printk(KERN_DEBUG "cyc:set_modem_info clearing "
+ "Z DTR\n");
#endif
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
} else {
return -ENODEV;
}
- CY_LOCK(info, flags);
- retval = cyz_issue_cmd(&cy_card[info->card],
- channel, C_CM_IOCTLM, 0L);
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
if (retval != 0) {
- printk("cyc:set_modem_info retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc:set_modem_info retval on ttyC%d "
+ "was %x\n", info->line, retval);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
} /* cy_tiocmset */
@@ -3820,14 +3749,17 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
*/
static void cy_break(struct tty_struct *tty, int break_state)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "cy_break"))
return;
- CY_LOCK(info, flags);
- if (!IS_CYC_Z(cy_card[info->card])) {
+ card = info->card;
+
+ spin_lock_irqsave(&card->card_lock, flags);
+ if (!IS_CYC_Z(*card)) {
/* Let the transmit ISR take care of this (since it
requires stuffing characters into the output stream).
*/
@@ -3835,18 +3767,18 @@ static void cy_break(struct tty_struct *tty, int break_state)
if (!info->breakon) {
info->breakon = 1;
if (!info->xmit_cnt) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
start_xmit(info);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
}
}
} else {
if (!info->breakoff) {
info->breakoff = 1;
if (!info->xmit_cnt) {
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
start_xmit(info);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
}
}
}
@@ -3854,24 +3786,25 @@ static void cy_break(struct tty_struct *tty, int break_state)
int retval;
if (break_state == -1) {
- retval = cyz_issue_cmd(&cy_card[info->card],
- info->line - cy_card[info->card].first_line,
+ retval = cyz_issue_cmd(card,
+ info->line - card->first_line,
C_CM_SET_BREAK, 0L);
if (retval != 0) {
- printk("cyc:cy_break (set) retval on ttyC%d "
- "was %x\n", info->line, retval);
+ printk(KERN_ERR "cyc:cy_break (set) retval on "
+ "ttyC%d was %x\n", info->line, retval);
}
} else {
- retval = cyz_issue_cmd(&cy_card[info->card],
- info->line - cy_card[info->card].first_line,
+ retval = cyz_issue_cmd(card,
+ info->line - card->first_line,
C_CM_CLR_BREAK, 0L);
if (retval != 0) {
- printk("cyc:cy_break (clr) retval on ttyC%d "
- "was %x\n", info->line, retval);
+ printk(KERN_DEBUG "cyc:cy_break (clr) retval "
+ "on ttyC%d was %x\n", info->line,
+ retval);
}
}
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} /* cy_break */
static int
@@ -3889,28 +3822,27 @@ get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
static int set_threshold(struct cyclades_port *info, unsigned long value)
{
+ struct cyclades_card *card;
void __iomem *base_addr;
- int card, channel, chip, index;
+ int channel, chip, index;
unsigned long flags;
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
+ index = card->bus_index;
base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ card->base_addr + (cy_chip_offset[chip] << index);
info->cor3 &= ~CyREC_FIFO;
info->cor3 |= value & CyREC_FIFO;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCOR3 << index), info->cor3);
cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR3ch, index);
- CY_UNLOCK(info, flags);
- } else {
- /* Nothing to do! */
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
} /* set_threshold */
@@ -3918,25 +3850,23 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
static int
get_threshold(struct cyclades_port *info, unsigned long __user * value)
{
+ struct cyclades_card *card;
void __iomem *base_addr;
- int card, channel, chip, index;
+ int channel, chip, index;
unsigned long tmp;
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- tmp = cy_readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
+ tmp = readb(base_addr + (CyCOR3 << index)) & CyREC_FIFO;
return put_user(tmp, value);
- } else {
- /* Nothing to do! */
- return 0;
}
+ return 0;
} /* get_threshold */
static int
@@ -3954,49 +3884,45 @@ get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
static int set_timeout(struct cyclades_port *info, unsigned long value)
{
+ struct cyclades_card *card;
void __iomem *base_addr;
- int card, channel, chip, index;
+ int channel, chip, index;
unsigned long flags;
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyRTPR << index), value & 0xff);
- CY_UNLOCK(info, flags);
- } else {
- /* Nothing to do! */
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
return 0;
} /* set_timeout */
static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
{
+ struct cyclades_card *card;
void __iomem *base_addr;
- int card, channel, chip, index;
+ int channel, chip, index;
unsigned long tmp;
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr =
- cy_card[card].base_addr + (cy_chip_offset[chip] << index);
+ index = card->bus_index;
+ base_addr = card->base_addr + (cy_chip_offset[chip] << index);
- tmp = cy_readb(base_addr + (CyRTPR << index));
+ tmp = readb(base_addr + (CyRTPR << index));
return put_user(tmp, value);
- } else {
- /* Nothing to do! */
- return 0;
}
+ return 0;
} /* get_timeout */
static int set_default_timeout(struct cyclades_port *info, unsigned long value)
@@ -4020,7 +3946,7 @@ static int
cy_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
struct cyclades_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser; /* user space */
int ret_val = 0;
@@ -4031,7 +3957,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
return -ENODEV;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); /* */
+ printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
+ info->line, cmd, arg);
#endif
switch (cmd) {
@@ -4076,14 +4003,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
case CYGETRTSDTR_INV:
ret_val = info->rtsdtr_inv;
break;
- case CYGETCARDINFO:
- if (copy_to_user(argp, &cy_card[info->card],
- sizeof(struct cyclades_card))) {
- ret_val = -EFAULT;
- break;
- }
- ret_val = 0;
- break;
case CYGETCD1400VER:
ret_val = info->chip_rev;
break;
@@ -4119,34 +4038,22 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
* Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&info->card->card_lock, flags);
/* note the counters on entry */
- cprev = info->icount;
- CY_UNLOCK(info, flags);
- while (1) {
- interruptible_sleep_on(&info->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current)) {
- return -ERESTARTSYS;
- }
-
- CY_LOCK(info, flags);
+ cnow = info->icount;
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
+ ret_val = wait_event_interruptible(info->delta_msr_wait, ({
+ cprev = cnow;
+ spin_lock_irqsave(&info->card->card_lock, flags);
cnow = info->icount; /* atomic copy */
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
- return -EIO; /* no change => error */
- }
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
- return 0;
- }
- cprev = cnow;
- }
- /* NOTREACHED */
+ ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts));
+ }));
+ break;
/*
* Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
@@ -4155,9 +4062,9 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
* RI where only 0->1 is counted.
*/
case TIOCGICOUNT:
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&info->card->card_lock, flags);
cnow = info->icount;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&info->card->card_lock, flags);
p_cuser = argp;
ret_val = put_user(cnow.cts, &p_cuser->cts);
if (ret_val)
@@ -4199,7 +4106,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
}
#ifdef CY_DEBUG_OTHER
- printk(" cyc:cy_ioctl done\n");
+ printk(KERN_DEBUG "cyc:cy_ioctl done\n");
#endif
return ret_val;
@@ -4213,10 +4120,10 @@ cy_ioctl(struct tty_struct *tty, struct file *file,
*/
static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_set_termios ttyC%d\n", info->line);
+ printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line);
#endif
if (tty->termios->c_cflag == old_termios->c_cflag &&
@@ -4248,8 +4155,9 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
*/
static void cy_send_xchar(struct tty_struct *tty, char ch)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, channel;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int channel;
if (serial_paranoia_check(info, tty->name, "cy_send_xchar"))
return;
@@ -4260,15 +4168,13 @@ static void cy_send_xchar(struct tty_struct *tty, char ch)
cy_start(tty);
card = info->card;
- channel = info->line - cy_card[card].first_line;
+ channel = info->line - card->first_line;
- if (IS_CYC_Z(cy_card[card])) {
+ if (IS_CYC_Z(*card)) {
if (ch == STOP_CHAR(tty))
- cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXOFF,
- 0L);
+ cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
else if (ch == START_CHAR(tty))
- cyz_issue_cmd(&cy_card[card], channel, C_CM_SENDXON,
- 0L);
+ cyz_issue_cmd(card, channel, C_CM_SENDXON, 0L);
}
}
@@ -4278,15 +4184,16 @@ static void cy_send_xchar(struct tty_struct *tty, char ch)
*/
static void cy_throttle(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
unsigned long flags;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
char buf[64];
- printk("cyc:throttle %s: %d....ttyC%d\n", tty_name(tty, buf),
+ printk(KERN_DEBUG "cyc:throttle %s: %ld...ttyC%d\n", tty_name(tty, buf),
tty->ldisc.chars_in_buffer(tty), info->line);
#endif
@@ -4297,22 +4204,22 @@ static void cy_throttle(struct tty_struct *tty)
card = info->card;
if (I_IXOFF(tty)) {
- if (!IS_CYC_Z(cy_card[card]))
+ if (!IS_CYC_Z(*card))
cy_send_xchar(tty, STOP_CHAR(tty));
else
info->throttle = 1;
}
if (tty->termios->c_cflag & CRTSCTS) {
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr +
+ index = card->bus_index;
+ base_addr = card->base_addr +
(cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -4322,7 +4229,7 @@ static void cy_throttle(struct tty_struct *tty)
cy_writeb(base_addr + (CyMSVR1 << index),
~CyRTS);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
info->throttle = 1;
}
@@ -4336,16 +4243,17 @@ static void cy_throttle(struct tty_struct *tty)
*/
static void cy_unthrottle(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
unsigned long flags;
void __iomem *base_addr;
- int card, chip, channel, index;
+ int chip, channel, index;
#ifdef CY_DEBUG_THROTTLE
char buf[64];
- printk("cyc:unthrottle %s: %d....ttyC%d\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty), info->line);
+ printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
+ tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty),info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) {
@@ -4361,15 +4269,15 @@ static void cy_unthrottle(struct tty_struct *tty)
if (tty->termios->c_cflag & CRTSCTS) {
card = info->card;
- channel = info->line - cy_card[card].first_line;
- if (!IS_CYC_Z(cy_card[card])) {
+ channel = info->line - card->first_line;
+ if (!IS_CYC_Z(*card)) {
chip = channel >> 2;
channel &= 0x03;
- index = cy_card[card].bus_index;
- base_addr = cy_card[card].base_addr +
+ index = card->bus_index;
+ base_addr = card->base_addr +
(cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char) channel);
if (info->rtsdtr_inv) {
@@ -4379,7 +4287,7 @@ static void cy_unthrottle(struct tty_struct *tty)
cy_writeb(base_addr + (CyMSVR1 << index),
CyRTS);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
} else {
info->throttle = 0;
}
@@ -4392,102 +4300,96 @@ static void cy_unthrottle(struct tty_struct *tty)
static void cy_stop(struct tty_struct *tty)
{
struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
void __iomem *base_addr;
int chip, channel, index;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_stop ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_stop ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_stop"))
return;
- cinfo = &cy_card[info->card];
+ cinfo = info->card;
channel = info->line - cinfo->first_line;
if (!IS_CYC_Z(*cinfo)) {
index = cinfo->bus_index;
chip = channel >> 2;
channel &= 0x03;
- base_addr = cy_card[info->card].base_addr +
- (cy_chip_offset[chip] << index);
+ base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&cinfo->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index),
(u_char)(channel & 0x0003)); /* index channel */
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) & ~CyTxRdy);
- CY_UNLOCK(info, flags);
- } else {
- /* Nothing to do! */
+ readb(base_addr + (CySRER << index)) & ~CyTxRdy);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_stop */
static void cy_start(struct tty_struct *tty)
{
struct cyclades_card *cinfo;
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
void __iomem *base_addr;
int chip, channel, index;
unsigned long flags;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_start ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_start ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_start"))
return;
- cinfo = &cy_card[info->card];
+ cinfo = info->card;
channel = info->line - cinfo->first_line;
index = cinfo->bus_index;
if (!IS_CYC_Z(*cinfo)) {
chip = channel >> 2;
channel &= 0x03;
- base_addr = cy_card[info->card].base_addr +
- (cy_chip_offset[chip] << index);
+ base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&cinfo->card_lock, flags);
cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */
cy_writeb(base_addr + (CySRER << index),
- cy_readb(base_addr + (CySRER << index)) | CyTxRdy);
- CY_UNLOCK(info, flags);
- } else {
- /* Nothing to do! */
+ readb(base_addr + (CySRER << index)) | CyTxRdy);
+ spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_start */
static void cy_flush_buffer(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
- int card, channel, retval;
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int channel, retval;
unsigned long flags;
#ifdef CY_DEBUG_IO
- printk("cyc:cy_flush_buffer ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
return;
card = info->card;
- channel = (info->line) - (cy_card[card].first_line);
+ channel = info->line - card->first_line;
- CY_LOCK(info, flags);
+ spin_lock_irqsave(&card->card_lock, flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
- if (IS_CYC_Z(cy_card[card])) { /* If it is a Z card, flush the on-board
+ if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
buffers as well */
- CY_LOCK(info, flags);
- retval =
- cyz_issue_cmd(&cy_card[card], channel, C_CM_FLUSH_TX, 0L);
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
if (retval != 0) {
- printk("cyc: flush_buffer retval on ttyC%d was %x\n",
- info->line, retval);
+ printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
+ "was %x\n", info->line, retval);
}
- CY_UNLOCK(info, flags);
+ spin_unlock_irqrestore(&card->card_lock, flags);
}
tty_wakeup(tty);
} /* cy_flush_buffer */
@@ -4497,10 +4399,10 @@ static void cy_flush_buffer(struct tty_struct *tty)
*/
static void cy_hangup(struct tty_struct *tty)
{
- struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
+ struct cyclades_port *info = tty->driver_data;
#ifdef CY_DEBUG_OTHER
- printk("cyc:cy_hangup ttyC%d\n", info->line); /* */
+ printk(KERN_DEBUG "cyc:cy_hangup ttyC%d\n", info->line);
#endif
if (serial_paranoia_check(info, tty->name, "cy_hangup"))
@@ -4511,7 +4413,8 @@ static void cy_hangup(struct tty_struct *tty)
info->event = 0;
info->count = 0;
#ifdef CY_DEBUG_COUNT
- printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid);
+ printk(KERN_DEBUG "cyc:cy_hangup (%d): setting count to 0\n",
+ current->pid);
#endif
info->tty = NULL;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
@@ -4526,10 +4429,107 @@ static void cy_hangup(struct tty_struct *tty)
* ---------------------------------------------------------------------
*/
+static int __devinit cy_init_card(struct cyclades_card *cinfo)
+{
+ struct cyclades_port *info;
+ u32 mailbox;
+ unsigned int nports;
+ unsigned short chip_number;
+ int index, port;
+
+ spin_lock_init(&cinfo->card_lock);
+
+ if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */
+ mailbox = readl(&((struct RUNTIME_9060 __iomem *)
+ cinfo->ctl_addr)->mail_box_0);
+ nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
+ cinfo->intr_enabled = 0;
+ cinfo->nports = 0; /* Will be correctly set later, after
+ Z FW is loaded */
+ } else {
+ index = cinfo->bus_index;
+ nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
+ }
+
+ cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL);
+ if (cinfo->ports == NULL) {
+ printk(KERN_ERR "Cyclades: cannot allocate ports\n");
+ cinfo->nports = 0;
+ return -ENOMEM;
+ }
+
+ for (port = cinfo->first_line; port < cinfo->first_line + nports;
+ port++) {
+ info = &cinfo->ports[port - cinfo->first_line];
+ info->magic = CYCLADES_MAGIC;
+ info->card = cinfo;
+ info->line = port;
+ info->flags = STD_COM_FLAGS;
+ info->closing_wait = CLOSING_WAIT_DELAY;
+ info->close_delay = 5 * HZ / 10;
+
+ INIT_WORK(&info->tqueue, do_softint);
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_completion(&info->shutdown_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+
+ if (IS_CYC_Z(*cinfo)) {
+ info->type = PORT_STARTECH;
+ if (mailbox == ZO_V1)
+ info->xmit_fifo_size = CYZ_FIFO_SIZE;
+ else
+ info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
+#ifdef CONFIG_CYZ_INTR
+ setup_timer(&cyz_rx_full_timer[port],
+ cyz_rx_restart, (unsigned long)info);
+#endif
+ } else {
+ info->type = PORT_CIRRUS;
+ info->xmit_fifo_size = CyMAX_CHAR_FIFO;
+ info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
+ info->cor2 = CyETC;
+ info->cor3 = 0x08; /* _very_ small rcv threshold */
+
+ chip_number = (port - cinfo->first_line) / 4;
+ if ((info->chip_rev = readb(cinfo->base_addr +
+ (cy_chip_offset[chip_number] <<
+ index) + (CyGFRCR << index))) >=
+ CD1400_REV_J) {
+ /* It is a CD1400 rev. J or later */
+ info->tbpr = baud_bpr_60[13]; /* Tx BPR */
+ info->tco = baud_co_60[13]; /* Tx CO */
+ info->rbpr = baud_bpr_60[13]; /* Rx BPR */
+ info->rco = baud_co_60[13]; /* Rx CO */
+ info->rtsdtr_inv = 1;
+ } else {
+ info->tbpr = baud_bpr_25[13]; /* Tx BPR */
+ info->tco = baud_co_25[13]; /* Tx CO */
+ info->rbpr = baud_bpr_25[13]; /* Rx BPR */
+ info->rco = baud_co_25[13]; /* Rx CO */
+ info->rtsdtr_inv = 0;
+ }
+ info->read_status_mask = CyTIMEOUT | CySPECHAR |
+ CyBREAK | CyPARITY | CyFRAME | CyOVERRUN;
+ }
+
+ }
+
+#ifndef CONFIG_CYZ_INTR
+ if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) {
+ mod_timer(&cyz_timerlist, jiffies + 1);
+#ifdef CY_PCI_DEBUG
+ printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
+#endif
+ }
+#endif
+ return 0;
+}
+
/* initialize chips on Cyclom-Y card -- return number of valid
chips (which is number of ports/4) */
-static unsigned short __init
-cyy_init_card(void __iomem * true_base_addr, int index)
+static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
+ int index)
{
unsigned int chip_number;
void __iomem *base_addr;
@@ -4544,7 +4544,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
base_addr =
true_base_addr + (cy_chip_offset[chip_number] << index);
mdelay(1);
- if (cy_readb(base_addr + (CyCCR << index)) != 0x00) {
+ if (readb(base_addr + (CyCCR << index)) != 0x00) {
/*************
printk(" chip #%d at %#6lx is never idle (CCR != 0)\n",
chip_number, (unsigned long)base_addr);
@@ -4561,7 +4561,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
chip 4 GFRCR register appears at chip 0, there is no chip 4
and this must be a Cyclom-16Y, not a Cyclom-32Ye.
*/
- if (chip_number == 4 && cy_readb(true_base_addr +
+ if (chip_number == 4 && readb(true_base_addr +
(cy_chip_offset[0] << index) +
(CyGFRCR << index)) == 0) {
return chip_number;
@@ -4570,7 +4570,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
cy_writeb(base_addr + (CyCCR << index), CyCHIP_RESET);
mdelay(1);
- if (cy_readb(base_addr + (CyGFRCR << index)) == 0x00) {
+ if (readb(base_addr + (CyGFRCR << index)) == 0x00) {
/*
printk(" chip #%d at %#6lx is not responding ",
chip_number, (unsigned long)base_addr);
@@ -4578,7 +4578,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
*/
return chip_number;
}
- if ((0xf0 & (cy_readb(base_addr + (CyGFRCR << index)))) !=
+ if ((0xf0 & (readb(base_addr + (CyGFRCR << index)))) !=
0x40) {
/*
printk(" chip #%d at %#6lx is not valid (GFRCR == "
@@ -4589,7 +4589,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
return chip_number;
}
cy_writeb(base_addr + (CyGCR << index), CyCH0_SERIAL);
- if (cy_readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
+ if (readb(base_addr + (CyGFRCR << index)) >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
/* Impossible to reach 5ms with this chip.
Changed to 2ms instead (f = 500 Hz). */
@@ -4602,7 +4602,7 @@ cyy_init_card(void __iomem * true_base_addr, int index)
/*
printk(" chip #%d at %#6lx is rev 0x%2x\n",
chip_number, (unsigned long)base_addr,
- cy_readb(base_addr+(CyGFRCR<<index)));
+ readb(base_addr+(CyGFRCR<<index)));
*/
}
return chip_number;
@@ -4647,9 +4647,15 @@ static int __init cy_detect_isa(void)
/* probe for CD1400... */
cy_isa_address = ioremap(isa_address, CyISA_Ywin);
+ if (cy_isa_address == NULL) {
+ printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
+ "address\n");
+ continue;
+ }
cy_isa_nchan = CyPORTS_PER_CHIP *
cyy_init_card(cy_isa_address, 0);
if (cy_isa_nchan == 0) {
+ iounmap(cy_isa_address);
continue;
}
#ifdef MODULE
@@ -4660,40 +4666,42 @@ static int __init cy_detect_isa(void)
/* find out the board's irq by probing */
cy_isa_irq = detect_isa_irq(cy_isa_address);
if (cy_isa_irq == 0) {
- printk("Cyclom-Y/ISA found at 0x%lx ",
+ printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but the "
+ "IRQ could not be detected.\n",
(unsigned long)cy_isa_address);
- printk("but the IRQ could not be detected.\n");
+ iounmap(cy_isa_address);
continue;
}
if ((cy_next_channel + cy_isa_nchan) > NR_PORTS) {
- printk("Cyclom-Y/ISA found at 0x%lx ",
+ printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
+ "more channels are available. Change NR_PORTS "
+ "in cyclades.c and recompile kernel.\n",
(unsigned long)cy_isa_address);
- printk("but no more channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and recompile "
- "kernel.\n");
+ iounmap(cy_isa_address);
return nboard;
}
/* fill the next cy_card structure available */
for (j = 0; j < NR_CARDS; j++) {
- if (cy_card[j].base_addr == 0)
+ if (cy_card[j].base_addr == NULL)
break;
}
if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/ISA found at 0x%lx ",
+ printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but no "
+ "more cards can be used. Change NR_CARDS in "
+ "cyclades.c and recompile kernel.\n",
(unsigned long)cy_isa_address);
- printk("but no more cards can be used .\n");
- printk("Change NR_CARDS in cyclades.c and recompile "
- "kernel.\n");
+ iounmap(cy_isa_address);
return nboard;
}
/* allocate IRQ */
if (request_irq(cy_isa_irq, cyy_interrupt,
IRQF_DISABLED, "Cyclom-Y", &cy_card[j])) {
- printk("Cyclom-Y/ISA found at 0x%lx ",
- (unsigned long)cy_isa_address);
- printk("but could not allocate IRQ#%d.\n", cy_isa_irq);
+ printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
+ "could not allocate IRQ#%d.\n",
+ (unsigned long)cy_isa_address, cy_isa_irq);
+ iounmap(cy_isa_address);
return nboard;
}
@@ -4704,15 +4712,23 @@ static int __init cy_detect_isa(void)
cy_card[j].bus_index = 0;
cy_card[j].first_line = cy_next_channel;
cy_card[j].num_chips = cy_isa_nchan / 4;
+ if (cy_init_card(&cy_card[j])) {
+ cy_card[j].base_addr = NULL;
+ free_irq(cy_isa_irq, &cy_card[j]);
+ iounmap(cy_isa_address);
+ continue;
+ }
nboard++;
- /* print message */
- printk("Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d, ",
+ printk(KERN_INFO "Cyclom-Y/ISA #%d: 0x%lx-0x%lx, IRQ%d found: "
+ "%d channels starting from port %d\n",
j + 1, (unsigned long)cy_isa_address,
(unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
- cy_isa_irq);
- printk("%d channels starting from port %d.\n",
- cy_isa_nchan, cy_next_channel);
+ cy_isa_irq, cy_isa_nchan, cy_next_channel);
+
+ for (j = cy_next_channel;
+ j < cy_next_channel + cy_isa_nchan; j++)
+ tty_register_device(cy_serial_driver, j, NULL);
cy_next_channel += cy_isa_nchan;
}
return nboard;
@@ -4721,510 +4737,310 @@ static int __init cy_detect_isa(void)
#endif /* CONFIG_ISA */
} /* cy_detect_isa */
-static void plx_init(void __iomem * addr, uclong initctl)
+#ifdef CONFIG_PCI
+static void __devinit plx_init(void __iomem * addr, __u32 initctl)
{
/* Reset PLX */
- cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x40000000);
+ cy_writel(addr + initctl, readl(addr + initctl) | 0x40000000);
udelay(100L);
- cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x40000000);
+ cy_writel(addr + initctl, readl(addr + initctl) & ~0x40000000);
/* Reload Config. Registers from EEPROM */
- cy_writel(addr + initctl, cy_readl(addr + initctl) | 0x20000000);
+ cy_writel(addr + initctl, readl(addr + initctl) | 0x20000000);
udelay(100L);
- cy_writel(addr + initctl, cy_readl(addr + initctl) & ~0x20000000);
+ cy_writel(addr + initctl, readl(addr + initctl) & ~0x20000000);
}
-/*
- * ---------------------------------------------------------------------
- * cy_detect_pci() - Test PCI bus presence and Cyclom-Ye/PCI.
- * sets global variables and return the number of PCI boards found.
- * ---------------------------------------------------------------------
- */
-static int __init cy_detect_pci(void)
+static int __devinit cy_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
-#ifdef CONFIG_PCI
-
- struct pci_dev *pdev = NULL;
- unsigned char cyy_rev_id;
- unsigned char cy_pci_irq = 0;
- uclong cy_pci_phys0, cy_pci_phys2;
- void __iomem *cy_pci_addr0, *cy_pci_addr2;
- unsigned short i, j, cy_pci_nchan, plx_ver;
- unsigned short device_id, dev_index = 0;
- uclong mailbox;
- uclong ZeIndex = 0;
- void __iomem *Ze_addr0[NR_CARDS], *Ze_addr2[NR_CARDS];
- uclong Ze_phys0[NR_CARDS], Ze_phys2[NR_CARDS];
- unsigned char Ze_irq[NR_CARDS];
- struct pci_dev *Ze_pdev[NR_CARDS];
-
- for (i = 0; i < NR_CARDS; i++) {
- /* look for a Cyclades card by vendor and device id */
- while ((device_id = cy_pci_dev_id[dev_index].device) != 0) {
- if ((pdev = pci_get_device(PCI_VENDOR_ID_CYCLADES,
- device_id, pdev)) == NULL) {
- dev_index++; /* try next device id */
- } else {
- break; /* found a board */
- }
- }
-
- if (device_id == 0)
- break;
-
- if (pci_enable_device(pdev))
- continue;
-
- /* read PCI configuration area */
- cy_pci_irq = pdev->irq;
- cy_pci_phys0 = pci_resource_start(pdev, 0);
- cy_pci_phys2 = pci_resource_start(pdev, 2);
- pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
+ void __iomem *addr0 = NULL, *addr2 = NULL;
+ char *card_name = NULL;
+ u32 mailbox;
+ unsigned int device_id, nchan = 0, card_no, i;
+ unsigned char plx_ver;
+ int retval, irq;
+
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ dev_err(&pdev->dev, "cannot enable device\n");
+ goto err;
+ }
- device_id &= ~PCI_DEVICE_ID_MASK;
+ /* read PCI configuration area */
+ irq = pdev->irq;
+ device_id = pdev->device & ~PCI_DEVICE_ID_MASK;
- if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
- device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
-#ifdef CY_PCI_DEBUG
- printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclom-Y/PCI:found winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
+#if defined(__alpha__)
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
+ dev_err(&pdev->dev, "Cyclom-Y/PCI not supported for low "
+ "addresses on Alpha systems.\n");
+ retval = -EIO;
+ goto err_dis;
+ }
#endif
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
+ dev_err(&pdev->dev, "Cyclades-Z/PCI not supported for low "
+ "addresses\n");
+ retval = -EIO;
+ goto err_dis;
+ }
- if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
- printk(" Warning: PCI I/O bit incorrectly "
- "set. Ignoring it...\n");
- pdev->resource[2].flags &= ~IORESOURCE_IO;
- }
+ if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
+ dev_warn(&pdev->dev, "PCI I/O bit incorrectly set. Ignoring "
+ "it...\n");
+ pdev->resource[2].flags &= ~IORESOURCE_IO;
+ }
- /* Although we don't use this I/O region, we should
- request it from the kernel anyway, to avoid problems
- with other drivers accessing it. */
- if (pci_request_regions(pdev, "Cyclom-Y") != 0) {
- printk(KERN_ERR "cyclades: failed to reserve "
- "PCI resources\n");
- continue;
- }
-#if defined(__alpha__)
- if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) { /* below 1M? */
- printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclom-Y/PCI:found winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2,
- (ulong)cy_pci_phys0);
- printk("Cyclom-Y/PCI not supported for low "
- "addresses in Alpha systems.\n");
- i--;
- continue;
- }
-#endif
- cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Yctl);
- cy_pci_addr2 = ioremap(cy_pci_phys2, CyPCI_Ywin);
+ retval = pci_request_regions(pdev, "cyclades");
+ if (retval) {
+ dev_err(&pdev->dev, "failed to reserve resources\n");
+ goto err_dis;
+ }
-#ifdef CY_PCI_DEBUG
- printk("Cyclom-Y/PCI: relocate winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (u_long)cy_pci_addr2, (u_long)cy_pci_addr0);
-#endif
- cy_pci_nchan = (unsigned short)(CyPORTS_PER_CHIP *
- cyy_init_card(cy_pci_addr2, 1));
- if (cy_pci_nchan == 0) {
- printk("Cyclom-Y PCI host card with ");
- printk("no Serial-Modules at 0x%lx.\n",
- (ulong) cy_pci_phys2);
- i--;
- continue;
- }
- if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but no channels are available.\n");
- printk("Change NR_PORTS in cyclades.c and "
- "recompile kernel.\n");
- return i;
- }
- /* fill the next cy_card structure available */
- for (j = 0; j < NR_CARDS; j++) {
- if (cy_card[j].base_addr == 0)
- break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but no more cards can be used.\n");
- printk("Change NR_CARDS in cyclades.c and "
- "recompile kernel.\n");
- return i;
- }
+ retval = -EIO;
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+ device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
+ card_name = "Cyclom-Y";
- /* allocate IRQ */
- if (request_irq(cy_pci_irq, cyy_interrupt,
- IRQF_SHARED, "Cyclom-Y", &cy_card[j])) {
- printk("Cyclom-Y/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but could not allocate IRQ%d.\n",
- cy_pci_irq);
- return i;
- }
+ addr0 = pci_iomap(pdev, 0, CyPCI_Yctl);
+ if (addr0 == NULL) {
+ dev_err(&pdev->dev, "can't remap ctl region\n");
+ goto err_reg;
+ }
+ addr2 = pci_iomap(pdev, 2, CyPCI_Ywin);
+ if (addr2 == NULL) {
+ dev_err(&pdev->dev, "can't remap base region\n");
+ goto err_unmap;
+ }
- /* set cy_card */
- cy_card[j].base_phys = (ulong) cy_pci_phys2;
- cy_card[j].ctl_phys = (ulong) cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int)cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = cy_pci_nchan / 4;
- cy_card[j].pdev = pdev;
-
- /* enable interrupts in the PCI interface */
- plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f;
- switch (plx_ver) {
- case PLX_9050:
-
- cy_writeb(cy_pci_addr0 + 0x4c, 0x43);
- break;
+ nchan = CyPORTS_PER_CHIP * cyy_init_card(addr2, 1);
+ if (nchan == 0) {
+ dev_err(&pdev->dev, "Cyclom-Y PCI host card with no "
+ "Serial-Modules\n");
+ return -EIO;
+ }
+ } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
+ struct RUNTIME_9060 __iomem *ctl_addr;
- case PLX_9060:
- case PLX_9080:
- default: /* Old boards, use PLX_9060 */
-
- plx_init(cy_pci_addr0, 0x6c);
- /* For some yet unknown reason, once the PLX9060 reloads
- the EEPROM, the IRQ is lost and, thus, we have to
- re-write it to the PCI config. registers.
- This will remain here until we find a permanent
- fix. */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
- cy_pci_irq);
-
- cy_writew(cy_pci_addr0 + 0x68,
- cy_readw(cy_pci_addr0 +
- 0x68) | 0x0900);
- break;
- }
+ ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl);
+ if (addr0 == NULL) {
+ dev_err(&pdev->dev, "can't remap ctl region\n");
+ goto err_reg;
+ }
- /* print message */
- printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
- j + 1, (ulong)cy_pci_phys2,
- (ulong) (cy_pci_phys2 + CyPCI_Ywin - 1),
- (int)cy_pci_irq);
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan, cy_next_channel);
-
- cy_next_channel += cy_pci_nchan;
- } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo) {
- /* print message */
- printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclades-Z/PCI: found winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (ulong)cy_pci_phys2, (ulong)cy_pci_phys0);
- printk("Cyclades-Z/PCI not supported for low "
- "addresses\n");
- break;
- } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) {
-#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ",
- pdev->bus->number, pdev->devfn);
- printk("rev_id=%d) IRQ%d\n",
- cyy_rev_id, (int)cy_pci_irq);
- printk("Cyclades-Z/PCI: found winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (ulong) cy_pci_phys2, (ulong) cy_pci_phys0);
-#endif
- cy_pci_addr0 = ioremap(cy_pci_phys0, CyPCI_Zctl);
-
- /* Disable interrupts on the PLX before resetting it */
- cy_writew(cy_pci_addr0 + 0x68,
- cy_readw(cy_pci_addr0 + 0x68) & ~0x0900);
-
- plx_init(cy_pci_addr0, 0x6c);
- /* For some yet unknown reason, once the PLX9060 reloads
- the EEPROM, the IRQ is lost and, thus, we have to
- re-write it to the PCI config. registers.
- This will remain here until we find a permanent
- fix. */
- pci_write_config_byte(pdev, PCI_INTERRUPT_LINE,
- cy_pci_irq);
-
- mailbox =
- (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_pci_addr0)->mail_box_0);
-
- if (pci_resource_flags(pdev, 2) & IORESOURCE_IO) {
- printk(" Warning: PCI I/O bit incorrectly "
- "set. Ignoring it...\n");
- pdev->resource[2].flags &= ~IORESOURCE_IO;
- }
+ /* Disable interrupts on the PLX before resetting it */
+ cy_writew(addr0 + 0x68,
+ readw(addr0 + 0x68) & ~0x0900);
+
+ plx_init(addr0, 0x6c);
+ /* For some yet unknown reason, once the PLX9060 reloads
+ the EEPROM, the IRQ is lost and, thus, we have to
+ re-write it to the PCI config. registers.
+ This will remain here until we find a permanent
+ fix. */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
+
+ mailbox = (u32)readl(&ctl_addr->mail_box_0);
+
+ addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ?
+ CyPCI_Ze_win : CyPCI_Zwin);
+ if (addr2 == NULL) {
+ dev_err(&pdev->dev, "can't remap base region\n");
+ goto err_unmap;
+ }
- /* Although we don't use this I/O region, we should
- request it from the kernel anyway, to avoid problems
- with other drivers accessing it. */
- if (pci_request_regions(pdev, "Cyclades-Z") != 0) {
- printk(KERN_ERR "cyclades: failed to reserve "
- "PCI resources\n");
- continue;
- }
+ if (mailbox == ZE_V1) {
+ card_name = "Cyclades-Ze";
- if (mailbox == ZE_V1) {
- cy_pci_addr2 = ioremap(cy_pci_phys2,
- CyPCI_Ze_win);
- if (ZeIndex == NR_CARDS) {
- printk("Cyclades-Ze/PCI found at "
- "0x%lx but no more cards can "
- "be used.\nChange NR_CARDS in "
- "cyclades.c and recompile "
- "kernel.\n",
- (ulong)cy_pci_phys2);
- } else {
- Ze_phys0[ZeIndex] = cy_pci_phys0;
- Ze_phys2[ZeIndex] = cy_pci_phys2;
- Ze_addr0[ZeIndex] = cy_pci_addr0;
- Ze_addr2[ZeIndex] = cy_pci_addr2;
- Ze_irq[ZeIndex] = cy_pci_irq;
- Ze_pdev[ZeIndex] = pdev;
- ZeIndex++;
- }
- i--;
- continue;
- } else {
- cy_pci_addr2 = ioremap(cy_pci_phys2,CyPCI_Zwin);
- }
+ readl(&ctl_addr->mail_box_0);
+ nchan = ZE_V1_NPORTS;
+ } else {
+ card_name = "Cyclades-8Zo";
#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI: relocate winaddr=0x%lx "
- "ctladdr=0x%lx\n",
- (ulong) cy_pci_addr2, (ulong) cy_pci_addr0);
if (mailbox == ZO_V1) {
- cy_writel(&((struct RUNTIME_9060 *)
- (cy_pci_addr0))->loc_addr_base,
- WIN_CREG);
- PAUSE;
- printk("Cyclades-8Zo/PCI: FPGA id %lx, ver "
- "%lx\n", (ulong) (0xff &
- cy_readl(&((struct CUSTOM_REG *)
- (cy_pci_addr2))->fpga_id)),
- (ulong)(0xff &
- cy_readl(&((struct CUSTOM_REG *)
- (cy_pci_addr2))->
- fpga_version)));
- cy_writel(&((struct RUNTIME_9060 *)
- (cy_pci_addr0))->loc_addr_base,
- WIN_RAM);
+ cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
+ dev_info(&pdev->dev, "Cyclades-8Zo/PCI: FPGA "
+ "id %lx, ver %lx\n", (ulong)(0xff &
+ readl(&((struct CUSTOM_REG *)addr2)->
+ fpga_id)), (ulong)(0xff &
+ readl(&((struct CUSTOM_REG *)addr2)->
+ fpga_version)));
+ cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
} else {
- printk("Cyclades-Z/PCI: New Cyclades-Z board. "
- "FPGA not loaded\n");
+ dev_info(&pdev->dev, "Cyclades-Z/PCI: New "
+ "Cyclades-Z board. FPGA not loaded\n");
}
#endif
/* The following clears the firmware id word. This
ensures that the driver will not attempt to talk to
the board until it has been properly initialized.
*/
- PAUSE;
if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
- cy_writel(cy_pci_addr2 + ID_ADDRESS, 0L);
+ cy_writel(addr2 + ID_ADDRESS, 0L);
/* This must be a Cyclades-8Zo/PCI. The extendable
version will have a different device_id and will
be allocated its maximum number of ports. */
- cy_pci_nchan = 8;
-
- if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
- printk("Cyclades-8Zo/PCI found at 0x%lx but"
- "no channels are available.\nChange "
- "NR_PORTS in cyclades.c and recompile "
- "kernel.\n", (ulong)cy_pci_phys2);
- return i;
- }
-
- /* fill the next cy_card structure available */
- for (j = 0; j < NR_CARDS; j++) {
- if (cy_card[j].base_addr == 0)
- break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclades-8Zo/PCI found at 0x%lx but"
- "no more cards can be used.\nChange "
- "NR_CARDS in cyclades.c and recompile "
- "kernel.\n", (ulong)cy_pci_phys2);
- return i;
- }
-#ifdef CONFIG_CYZ_INTR
- /* allocate IRQ only if board has an IRQ */
- if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
- if (request_irq(cy_pci_irq, cyz_interrupt,
- IRQF_SHARED, "Cyclades-Z",
- &cy_card[j])) {
- printk("Cyclom-8Zo/PCI found at 0x%lx "
- "but could not allocate "
- "IRQ%d.\n", (ulong)cy_pci_phys2,
- cy_pci_irq);
- return i;
- }
- }
-#endif /* CONFIG_CYZ_INTR */
-
- /* set cy_card */
- cy_card[j].base_phys = cy_pci_phys2;
- cy_card[j].ctl_phys = cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int)cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = -1;
- cy_card[j].pdev = pdev;
-
- /* print message */
-#ifdef CONFIG_CYZ_INTR
- /* don't report IRQ if board is no IRQ */
- if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
- printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, "
- "IRQ%d, ", j + 1, (ulong)cy_pci_phys2,
- (ulong) (cy_pci_phys2 + CyPCI_Zwin - 1),
- (int)cy_pci_irq);
- else
-#endif /* CONFIG_CYZ_INTR */
- printk("Cyclades-8Zo/PCI #%d: 0x%lx-0x%lx, ",
- j + 1, (ulong)cy_pci_phys2,
- (ulong)(cy_pci_phys2 + CyPCI_Zwin - 1));
-
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan, cy_next_channel);
- cy_next_channel += cy_pci_nchan;
+ nchan = 8;
}
}
- for (; ZeIndex != 0 && i < NR_CARDS; i++) {
- cy_pci_phys0 = Ze_phys0[0];
- cy_pci_phys2 = Ze_phys2[0];
- cy_pci_addr0 = Ze_addr0[0];
- cy_pci_addr2 = Ze_addr2[0];
- cy_pci_irq = Ze_irq[0];
- pdev = Ze_pdev[0];
- for (j = 0; j < ZeIndex - 1; j++) {
- Ze_phys0[j] = Ze_phys0[j + 1];
- Ze_phys2[j] = Ze_phys2[j + 1];
- Ze_addr0[j] = Ze_addr0[j + 1];
- Ze_addr2[j] = Ze_addr2[j + 1];
- Ze_irq[j] = Ze_irq[j + 1];
- Ze_pdev[j] = Ze_pdev[j + 1];
- }
- ZeIndex--;
- mailbox = (uclong)cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_pci_addr0)->mail_box_0);
-#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n",
- (ulong)cy_pci_addr2, (ulong)cy_pci_addr0);
- printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not "
- "loaded\n");
-#endif
- PAUSE;
- /* This must be the new Cyclades-Ze/PCI. */
- cy_pci_nchan = ZE_V1_NPORTS;
-
- if ((cy_next_channel + cy_pci_nchan) > NR_PORTS) {
- printk("Cyclades-Ze/PCI found at 0x%lx but no channels "
- "are available.\nChange NR_PORTS in cyclades.c "
- "and recompile kernel.\n",
- (ulong) cy_pci_phys2);
- return i;
- }
+ if ((cy_next_channel + nchan) > NR_PORTS) {
+ dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
+ "channels are available. Change NR_PORTS in "
+ "cyclades.c and recompile kernel.\n");
+ goto err_unmap;
+ }
+ /* fill the next cy_card structure available */
+ for (card_no = 0; card_no < NR_CARDS; card_no++) {
+ if (cy_card[card_no].base_addr == NULL)
+ break;
+ }
+ if (card_no == NR_CARDS) { /* no more cy_cards available */
+ dev_err(&pdev->dev, "Cyclades-8Zo/PCI found, but no "
+ "more cards can be used. Change NR_CARDS in "
+ "cyclades.c and recompile kernel.\n");
+ goto err_unmap;
+ }
- /* fill the next cy_card structure available */
- for (j = 0; j < NR_CARDS; j++) {
- if (cy_card[j].base_addr == 0)
- break;
- }
- if (j == NR_CARDS) { /* no more cy_cards available */
- printk("Cyclades-Ze/PCI found at 0x%lx but no more "
- "cards can be used.\nChange NR_CARDS in "
- "cyclades.c and recompile kernel.\n",
- (ulong) cy_pci_phys2);
- return i;
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+ device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
+ /* allocate IRQ */
+ retval = request_irq(irq, cyy_interrupt,
+ IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
+ if (retval) {
+ dev_err(&pdev->dev, "could not allocate IRQ\n");
+ goto err_unmap;
}
+ cy_card[card_no].num_chips = nchan / 4;
+ } else {
#ifdef CONFIG_CYZ_INTR
/* allocate IRQ only if board has an IRQ */
- if ((cy_pci_irq != 0) && (cy_pci_irq != 255)) {
- if (request_irq(cy_pci_irq, cyz_interrupt,
+ if (irq != 0 && irq != 255) {
+ retval = request_irq(irq, cyz_interrupt,
IRQF_SHARED, "Cyclades-Z",
- &cy_card[j])) {
- printk("Cyclom-Ze/PCI found at 0x%lx ",
- (ulong) cy_pci_phys2);
- printk("but could not allocate IRQ%d.\n",
- cy_pci_irq);
- return i;
+ &cy_card[card_no]);
+ if (retval) {
+ dev_err(&pdev->dev, "could not allocate IRQ\n");
+ goto err_unmap;
}
}
#endif /* CONFIG_CYZ_INTR */
+ cy_card[card_no].num_chips = -1;
+ }
- /* set cy_card */
- cy_card[j].base_phys = cy_pci_phys2;
- cy_card[j].ctl_phys = cy_pci_phys0;
- cy_card[j].base_addr = cy_pci_addr2;
- cy_card[j].ctl_addr = cy_pci_addr0;
- cy_card[j].irq = (int)cy_pci_irq;
- cy_card[j].bus_index = 1;
- cy_card[j].first_line = cy_next_channel;
- cy_card[j].num_chips = -1;
- cy_card[j].pdev = pdev;
+ /* set cy_card */
+ cy_card[card_no].base_addr = addr2;
+ cy_card[card_no].ctl_addr = addr0;
+ cy_card[card_no].irq = irq;
+ cy_card[card_no].bus_index = 1;
+ cy_card[card_no].first_line = cy_next_channel;
+ retval = cy_init_card(&cy_card[card_no]);
+ if (retval)
+ goto err_null;
- /* print message */
-#ifdef CONFIG_CYZ_INTR
- /* don't report IRQ if board is no IRQ */
- if ((cy_pci_irq != 0) && (cy_pci_irq != 255))
- printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, IRQ%d, ",
- j + 1, (ulong) cy_pci_phys2,
- (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1),
- (int)cy_pci_irq);
- else
-#endif /* CONFIG_CYZ_INTR */
- printk("Cyclades-Ze/PCI #%d: 0x%lx-0x%lx, ",
- j + 1, (ulong) cy_pci_phys2,
- (ulong) (cy_pci_phys2 + CyPCI_Ze_win - 1));
+ pci_set_drvdata(pdev, &cy_card[card_no]);
- printk("%d channels starting from port %d.\n",
- cy_pci_nchan, cy_next_channel);
- cy_next_channel += cy_pci_nchan;
- }
- if (ZeIndex != 0) {
- printk("Cyclades-Ze/PCI found at 0x%x but no more cards can be "
- "used.\nChange NR_CARDS in cyclades.c and recompile "
- "kernel.\n", (unsigned int)Ze_phys2[0]);
+ if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
+ device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
+ /* enable interrupts in the PCI interface */
+ plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
+ switch (plx_ver) {
+ case PLX_9050:
+
+ cy_writeb(addr0 + 0x4c, 0x43);
+ break;
+
+ case PLX_9060:
+ case PLX_9080:
+ default: /* Old boards, use PLX_9060 */
+
+ plx_init(addr0, 0x6c);
+ /* For some yet unknown reason, once the PLX9060 reloads
+ the EEPROM, the IRQ is lost and, thus, we have to
+ re-write it to the PCI config. registers.
+ This will remain here until we find a permanent
+ fix. */
+ pci_write_config_byte(pdev, PCI_INTERRUPT_LINE, irq);
+
+ cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900);
+ break;
+ }
}
- return i;
-#else
+
+ dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
+ "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
+ for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
+ tty_register_device(cy_serial_driver, i, &pdev->dev);
+ cy_next_channel += nchan;
+
return 0;
-#endif /* ifdef CONFIG_PCI */
-} /* cy_detect_pci */
+err_null:
+ cy_card[card_no].base_addr = NULL;
+ free_irq(irq, &cy_card[card_no]);
+err_unmap:
+ pci_iounmap(pdev, addr0);
+ if (addr2)
+ pci_iounmap(pdev, addr2);
+err_reg:
+ pci_release_regions(pdev);
+err_dis:
+ pci_disable_device(pdev);
+err:
+ return retval;
+}
-/*
- * This routine prints out the appropriate serial driver version number
- * and identifies which options were configured into this driver.
- */
-static inline void show_version(void)
+static void __devexit cy_pci_remove(struct pci_dev *pdev)
{
- printk("Cyclades driver " CY_VERSION "\n");
- printk(" built %s %s\n", __DATE__, __TIME__);
-} /* show_version */
+ struct cyclades_card *cinfo = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ /* non-Z with old PLX */
+ if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
+ PLX_9050)
+ cy_writeb(cinfo->ctl_addr + 0x4c, 0);
+ else
+#ifndef CONFIG_CYZ_INTR
+ if (!IS_CYC_Z(*cinfo))
+#endif
+ cy_writew(cinfo->ctl_addr + 0x68,
+ readw(cinfo->ctl_addr + 0x68) & ~0x0900);
+
+ pci_iounmap(pdev, cinfo->base_addr);
+ if (cinfo->ctl_addr)
+ pci_iounmap(pdev, cinfo->ctl_addr);
+ if (cinfo->irq
+#ifndef CONFIG_CYZ_INTR
+ && !IS_CYC_Z(*cinfo)
+#endif /* CONFIG_CYZ_INTR */
+ )
+ free_irq(cinfo->irq, cinfo);
+ pci_release_regions(pdev);
+
+ cinfo->base_addr = NULL;
+ for (i = cinfo->first_line; i < cinfo->first_line +
+ cinfo->nports; i++)
+ tty_unregister_device(cy_serial_driver, i);
+ cinfo->nports = 0;
+ kfree(cinfo->ports);
+}
+
+static struct pci_driver cy_pci_driver = {
+ .name = "cyclades",
+ .id_table = cy_pci_dev_id,
+ .probe = cy_pci_probe,
+ .remove = __devexit_p(cy_pci_remove)
+};
+#endif
static int
cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
int *eof, void *data)
{
struct cyclades_port *info;
- int i;
+ unsigned int i, j;
int len = 0;
off_t begin = 0;
off_t pos = 0;
@@ -5238,33 +5054,34 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length,
len += size;
/* Output one line for each known port */
- for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) {
- info = &cy_port[i];
-
- if (info->count)
- size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
- "%8lu %9lu %6ld\n", info->line,
- (cur_jifs - info->idle_stats.in_use) / HZ,
- info->idle_stats.xmit_bytes,
- (cur_jifs - info->idle_stats.xmit_idle) / HZ,
- info->idle_stats.recv_bytes,
- (cur_jifs - info->idle_stats.recv_idle) / HZ,
- info->idle_stats.overruns,
- (long)info->tty->ldisc.num);
- else
- size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu "
- "%8lu %9lu %6ld\n",
- info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
- len += size;
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
+ for (i = 0; i < NR_CARDS; i++)
+ for (j = 0; j < cy_card[i].nports; j++) {
+ info = &cy_card[i].ports[j];
+
+ if (info->count)
+ size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+ "%10lu %8lu %9lu %6ld\n", info->line,
+ (cur_jifs - info->idle_stats.in_use) /
+ HZ, info->idle_stats.xmit_bytes,
+ (cur_jifs - info->idle_stats.xmit_idle)/
+ HZ, info->idle_stats.recv_bytes,
+ (cur_jifs - info->idle_stats.recv_idle)/
+ HZ, info->idle_stats.overruns,
+ (long)info->tty->ldisc.num);
+ else
+ size = sprintf(buf + len, "%3d %8lu %10lu %8lu "
+ "%10lu %8lu %9lu %6ld\n",
+ info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto done;
}
- if (pos > offset + length)
- goto done;
- }
*eof = 1;
done:
*start = buf + (offset - begin); /* Start of wanted data */
@@ -5319,18 +5136,15 @@ static const struct tty_operations cy_ops = {
static int __init cy_init(void)
{
- struct cyclades_port *info;
- struct cyclades_card *cinfo;
- int number_z_boards = 0;
- int board, port, i, index;
- unsigned long mailbox;
- unsigned short chip_number;
- int nports;
+ unsigned int nboards;
+ int retval = -ENOMEM;
cy_serial_driver = alloc_tty_driver(NR_PORTS);
if (!cy_serial_driver)
- return -ENOMEM;
- show_version();
+ goto err;
+
+ printk(KERN_INFO "Cyclades driver " CY_VERSION " (built %s %s)\n",
+ __DATE__, __TIME__);
/* Initialize the tty_driver structure */
@@ -5344,15 +5158,13 @@ static int __init cy_init(void)
cy_serial_driver->init_termios = tty_std_termios;
cy_serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- cy_serial_driver->flags = TTY_DRIVER_REAL_RAW;
+ cy_serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(cy_serial_driver, &cy_ops);
- if (tty_register_driver(cy_serial_driver))
- panic("Couldn't register Cyclades serial driver\n");
-
- for (i = 0; i < NR_CARDS; i++) {
- /* base_addr=0 indicates board not found */
- cy_card[i].base_addr = NULL;
+ retval = tty_register_driver(cy_serial_driver);
+ if (retval) {
+ printk(KERN_ERR "Couldn't register Cyclades serial driver\n");
+ goto err_frtty;
}
/* the code below is responsible to find the boards. Each different
@@ -5363,223 +5175,68 @@ static int __init cy_init(void)
the cy_next_channel. */
/* look for isa boards */
- cy_isa_nboard = cy_detect_isa();
+ nboards = cy_detect_isa();
+#ifdef CONFIG_PCI
/* look for pci boards */
- cy_pci_nboard = cy_detect_pci();
-
- cy_nboard = cy_isa_nboard + cy_pci_nboard;
-
- /* invalidate remaining cy_card structures */
- for (i = 0; i < NR_CARDS; i++) {
- if (cy_card[i].base_addr == 0) {
- cy_card[i].first_line = -1;
- cy_card[i].ctl_addr = NULL;
- cy_card[i].irq = 0;
- cy_card[i].bus_index = 0;
- cy_card[i].first_line = 0;
- cy_card[i].num_chips = 0;
- }
- }
- /* invalidate remaining cy_port structures */
- for (i = cy_next_channel; i < NR_PORTS; i++) {
- cy_port[i].line = -1;
- cy_port[i].magic = -1;
- }
-
- /* initialize per-port data structures for each valid board found */
- for (board = 0; board < cy_nboard; board++) {
- cinfo = &cy_card[board];
- if (cinfo->num_chips == -1) { /* Cyclades-Z */
- number_z_boards++;
- mailbox = cy_readl(&((struct RUNTIME_9060 __iomem *)
- cy_card[board].ctl_addr)->
- mail_box_0);
- nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
- cinfo->intr_enabled = 0;
- cinfo->nports = 0; /* Will be correctly set later, after
- Z FW is loaded */
- spin_lock_init(&cinfo->card_lock);
- for (port = cinfo->first_line;
- port < cinfo->first_line + nports; port++) {
- info = &cy_port[port];
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_STARTECH;
- info->card = board;
- info->line = port;
- info->chip_rev = 0;
- info->flags = STD_COM_FLAGS;
- info->tty = NULL;
- if (mailbox == ZO_V1)
- info->xmit_fifo_size = CYZ_FIFO_SIZE;
- else
- info->xmit_fifo_size =
- 4 * CYZ_FIFO_SIZE;
- info->cor1 = 0;
- info->cor2 = 0;
- info->cor3 = 0;
- info->cor4 = 0;
- info->cor5 = 0;
- info->tbpr = 0;
- info->tco = 0;
- info->rbpr = 0;
- info->rco = 0;
- info->custom_divisor = 0;
- info->close_delay = 5 * HZ / 10;
- info->closing_wait = CLOSING_WAIT_DELAY;
- info->icount.cts = info->icount.dsr =
- info->icount.rng = info->icount.dcd = 0;
- info->icount.rx = info->icount.tx = 0;
- info->icount.frame = info->icount.parity = 0;
- info->icount.overrun = info->icount.brk = 0;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- INIT_WORK(&info->tqueue, do_softint);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->shutdown_wait);
- init_waitqueue_head(&info->delta_msr_wait);
- /* info->session */
- /* info->pgrp */
- info->read_status_mask = 0;
- /* info->timeout */
- /* Bentson's vars */
- info->jiffies[0] = 0;
- info->jiffies[1] = 0;
- info->jiffies[2] = 0;
- info->rflush_count = 0;
-#ifdef CONFIG_CYZ_INTR
- init_timer(&cyz_rx_full_timer[port]);
- cyz_rx_full_timer[port].function = NULL;
+ retval = pci_register_driver(&cy_pci_driver);
+ if (retval && !nboards)
+ goto err_unr;
#endif
- }
- continue;
- } else { /* Cyclom-Y of some kind */
- index = cinfo->bus_index;
- spin_lock_init(&cinfo->card_lock);
- cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
- for (port = cinfo->first_line;
- port < cinfo->first_line + cinfo->nports; port++) {
- info = &cy_port[port];
- info->magic = CYCLADES_MAGIC;
- info->type = PORT_CIRRUS;
- info->card = board;
- info->line = port;
- info->flags = STD_COM_FLAGS;
- info->tty = NULL;
- info->xmit_fifo_size = CyMAX_CHAR_FIFO;
- info->cor1 =
- CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
- info->cor2 = CyETC;
- info->cor3 = 0x08; /* _very_ small rcv threshold */
- info->cor4 = 0;
- info->cor5 = 0;
- info->custom_divisor = 0;
- info->close_delay = 5 * HZ / 10;
- info->closing_wait = CLOSING_WAIT_DELAY;
- info->icount.cts = info->icount.dsr =
- info->icount.rng = info->icount.dcd = 0;
- info->icount.rx = info->icount.tx = 0;
- info->icount.frame = info->icount.parity = 0;
- info->icount.overrun = info->icount.brk = 0;
- chip_number = (port - cinfo->first_line) / 4;
- if ((info->chip_rev =
- cy_readb(cinfo->base_addr +
- (cy_chip_offset[chip_number] <<
- index) + (CyGFRCR << index))) >=
- CD1400_REV_J) {
- /* It is a CD1400 rev. J or later */
- info->tbpr = baud_bpr_60[13]; /* Tx BPR */
- info->tco = baud_co_60[13]; /* Tx CO */
- info->rbpr = baud_bpr_60[13]; /* Rx BPR */
- info->rco = baud_co_60[13]; /* Rx CO */
- info->rflow = 0;
- info->rtsdtr_inv = 1;
- } else {
- info->tbpr = baud_bpr_25[13]; /* Tx BPR */
- info->tco = baud_co_25[13]; /* Tx CO */
- info->rbpr = baud_bpr_25[13]; /* Rx BPR */
- info->rco = baud_co_25[13]; /* Rx CO */
- info->rflow = 0;
- info->rtsdtr_inv = 0;
- }
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- info->default_threshold = 0;
- info->default_timeout = 0;
- INIT_WORK(&info->tqueue, do_softint);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- init_waitqueue_head(&info->shutdown_wait);
- init_waitqueue_head(&info->delta_msr_wait);
- /* info->session */
- /* info->pgrp */
- info->read_status_mask =
- CyTIMEOUT | CySPECHAR | CyBREAK
- | CyPARITY | CyFRAME | CyOVERRUN;
- /* info->timeout */
- }
- }
- }
-
-#ifndef CONFIG_CYZ_INTR
- if (number_z_boards && !cyz_timeron) {
- cyz_timeron++;
- cyz_timerlist.expires = jiffies + 1;
- add_timer(&cyz_timerlist);
-#ifdef CY_PCI_DEBUG
- printk("Cyclades-Z polling initialized\n");
-#endif
- }
-#endif /* CONFIG_CYZ_INTR */
return 0;
-
+err_unr:
+ tty_unregister_driver(cy_serial_driver);
+err_frtty:
+ put_tty_driver(cy_serial_driver);
+err:
+ return retval;
} /* cy_init */
static void __exit cy_cleanup_module(void)
{
+ struct cyclades_card *card;
int i, e1;
#ifndef CONFIG_CYZ_INTR
- if (cyz_timeron){
- cyz_timeron = 0;
- del_timer(&cyz_timerlist);
- }
+ del_timer_sync(&cyz_timerlist);
#endif /* CONFIG_CYZ_INTR */
if ((e1 = tty_unregister_driver(cy_serial_driver)))
- printk("cyc: failed to unregister Cyclades serial driver(%d)\n",
- e1);
+ printk(KERN_ERR "failed to unregister Cyclades serial "
+ "driver(%d)\n", e1);
- put_tty_driver(cy_serial_driver);
+#ifdef CONFIG_PCI
+ pci_unregister_driver(&cy_pci_driver);
+#endif
for (i = 0; i < NR_CARDS; i++) {
- if (cy_card[i].base_addr) {
- iounmap(cy_card[i].base_addr);
- if (cy_card[i].ctl_addr)
- iounmap(cy_card[i].ctl_addr);
- if (cy_card[i].irq
+ card = &cy_card[i];
+ if (card->base_addr) {
+ /* clear interrupt */
+ cy_writeb(card->base_addr + Cy_ClrIntr, 0);
+ iounmap(card->base_addr);
+ if (card->ctl_addr)
+ iounmap(card->ctl_addr);
+ if (card->irq
#ifndef CONFIG_CYZ_INTR
- && cy_card[i].num_chips != -1 /* not a Z card */
+ && !IS_CYC_Z(*card)
#endif /* CONFIG_CYZ_INTR */
)
- free_irq(cy_card[i].irq, &cy_card[i]);
-#ifdef CONFIG_PCI
- if (cy_card[i].pdev)
- pci_release_regions(cy_card[i].pdev);
-#endif
+ free_irq(card->irq, card);
+ for (e1 = card->first_line;
+ e1 < card->first_line +
+ card->nports; e1++)
+ tty_unregister_device(cy_serial_driver, e1);
+ kfree(card->ports);
}
}
+
+ put_tty_driver(cy_serial_driver);
} /* cy_cleanup_module */
module_init(cy_init);
module_exit(cy_cleanup_module);
MODULE_LICENSE("GPL");
+MODULE_VERSION(CY_VERSION);
diff --git a/drivers/char/digi.h b/drivers/char/digi.h
deleted file mode 100644
index 19df0e879b1..00000000000
--- a/drivers/char/digi.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/* Definitions for DigiBoard ditty(1) command. */
-
-#if !defined(TIOCMODG)
-#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */
-#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */
-#endif
-
-#if !defined(TIOCMSET)
-#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */
-#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */
-#endif
-
-#if !defined(TIOCMBIC)
-#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */
-#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */
-#endif
-
-#if !defined(TIOCSDTR)
-#define TIOCSDTR (('e'<<8) | 0) /* set DTR */
-#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */
-#endif
-
-/************************************************************************
- * Ioctl command arguments for DIGI parameters.
- ************************************************************************/
-#define DIGI_GETA (('e'<<8) | 94) /* Read params */
-
-#define DIGI_SETA (('e'<<8) | 95) /* Set params */
-#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */
-#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */
-
-#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */
- /* control characters */
-#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */
- /* control characters */
-#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */
- /* flow control chars */
-#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */
- /* flow control chars */
-
-struct digiflow_struct {
- unsigned char startc; /* flow cntl start char */
- unsigned char stopc; /* flow cntl stop char */
-};
-
-typedef struct digiflow_struct digiflow_t;
-
-
-/************************************************************************
- * Values for digi_flags
- ************************************************************************/
-#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */
-#define DIGI_FAST 0x0002 /* Fast baud rates */
-#define RTSPACE 0x0004 /* RTS input flow control */
-#define CTSPACE 0x0008 /* CTS output flow control */
-#define DSRPACE 0x0010 /* DSR output flow control */
-#define DCDPACE 0x0020 /* DCD output flow control */
-#define DTRPACE 0x0040 /* DTR input flow control */
-#define DIGI_FORCEDCD 0x0100 /* Force carrier */
-#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */
-#define DIGI_AIXON 0x0400 /* Aux flow control in fep */
-
-
-/************************************************************************
- * Structure used with ioctl commands for DIGI parameters.
- ************************************************************************/
-struct digi_struct {
- unsigned short digi_flags; /* Flags (see above) */
-};
-
-typedef struct digi_struct digi_t;
diff --git a/drivers/char/drm/README.drm b/drivers/char/drm/README.drm
index 6441e01e587..af74cd79a27 100644
--- a/drivers/char/drm/README.drm
+++ b/drivers/char/drm/README.drm
@@ -1,6 +1,6 @@
************************************************************
* For the very latest on DRI development, please see: *
-* http://dri.sourceforge.net/ *
+* http://dri.freedesktop.org/ *
************************************************************
The Direct Rendering Manager (drm) is a device-independent kernel-level
@@ -26,21 +26,19 @@ ways:
Documentation on the DRI is available from:
- http://precisioninsight.com/piinsights.html
+ http://dri.freedesktop.org/wiki/Documentation
+ http://sourceforge.net/project/showfiles.php?group_id=387
+ http://dri.sourceforge.net/doc/
For specific information about kernel-level support, see:
The Direct Rendering Manager, Kernel Support for the Direct Rendering
Infrastructure
- http://precisioninsight.com/dr/drm.html
+ http://dri.sourceforge.net/doc/drm_low_level.html
Hardware Locking for the Direct Rendering Infrastructure
- http://precisioninsight.com/dr/locking.html
+ http://dri.sourceforge.net/doc/hardware_locking_low_level.html
A Security Analysis of the Direct Rendering Infrastructure
- http://precisioninsight.com/dr/security.html
+ http://dri.sourceforge.net/doc/security_low_level.html
-************************************************************
-* For the very latest on DRI development, please see: *
-* http://dri.sourceforge.net/ *
-************************************************************
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index bd7be09ea53..5b91bc04ea4 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -33,59 +33,44 @@
#include "drmP.h"
-#if PAGE_SIZE == 65536
-# define ATI_PCIGART_TABLE_ORDER 0
-# define ATI_PCIGART_TABLE_PAGES (1 << 0)
-#elif PAGE_SIZE == 16384
-# define ATI_PCIGART_TABLE_ORDER 1
-# define ATI_PCIGART_TABLE_PAGES (1 << 1)
-#elif PAGE_SIZE == 8192
-# define ATI_PCIGART_TABLE_ORDER 2
-# define ATI_PCIGART_TABLE_PAGES (1 << 2)
-#elif PAGE_SIZE == 4096
-# define ATI_PCIGART_TABLE_ORDER 3
-# define ATI_PCIGART_TABLE_PAGES (1 << 3)
-#else
-# error - PAGE_SIZE not 64K, 16K, 8K or 4K
-#endif
-
-# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */
# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
-static void *drm_ati_alloc_pcigart_table(void)
+static void *drm_ati_alloc_pcigart_table(int order)
{
unsigned long address;
struct page *page;
int i;
- DRM_DEBUG("%s\n", __FUNCTION__);
+
+ DRM_DEBUG("%s: alloc %d order\n", __FUNCTION__, order);
address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
- ATI_PCIGART_TABLE_ORDER);
+ order);
if (address == 0UL) {
return NULL;
}
page = virt_to_page(address);
- for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
+ for (i = 0; i < order; i++, page++)
SetPageReserved(page);
DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address);
return (void *)address;
}
-static void drm_ati_free_pcigart_table(void *address)
+static void drm_ati_free_pcigart_table(void *address, int order)
{
struct page *page;
int i;
+ int num_pages = 1 << order;
DRM_DEBUG("%s\n", __FUNCTION__);
page = virt_to_page((unsigned long)address);
- for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
+ for (i = 0; i < num_pages; i++, page++)
ClearPageReserved(page);
- free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER);
+ free_pages((unsigned long)address, order);
}
int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
@@ -93,6 +78,8 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
drm_sg_mem_t *entry = dev->sg;
unsigned long pages;
int i;
+ int order;
+ int num_pages, max_pages;
/* we need to support large memory configurations */
if (!entry) {
@@ -100,15 +87,19 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
return 0;
}
+ order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE);
+ num_pages = 1 << order;
+
if (gart_info->bus_addr) {
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
pci_unmap_single(dev->pdev, gart_info->bus_addr,
- ATI_PCIGART_TABLE_PAGES * PAGE_SIZE,
+ num_pages * PAGE_SIZE,
PCI_DMA_TODEVICE);
}
- pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
- ? entry->pages : ATI_MAX_PCIGART_PAGES;
+ max_pages = (gart_info->table_size / sizeof(u32));
+ pages = (entry->pages <= max_pages)
+ ? entry->pages : max_pages;
for (i = 0; i < pages; i++) {
if (!entry->busaddr[i])
@@ -123,13 +114,12 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN
&& gart_info->addr) {
- drm_ati_free_pcigart_table(gart_info->addr);
+ drm_ati_free_pcigart_table(gart_info->addr, order);
gart_info->addr = NULL;
}
return 1;
}
-
EXPORT_SYMBOL(drm_ati_pcigart_cleanup);
int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
@@ -139,6 +129,9 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
unsigned long pages;
u32 *pci_gart, page_base, bus_address = 0;
int i, j, ret = 0;
+ int order;
+ int max_pages;
+ int num_pages;
if (!entry) {
DRM_ERROR("no scatter/gather memory!\n");
@@ -148,7 +141,10 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
- address = drm_ati_alloc_pcigart_table();
+ order = drm_order((gart_info->table_size +
+ (PAGE_SIZE-1)) / PAGE_SIZE);
+ num_pages = 1 << order;
+ address = drm_ati_alloc_pcigart_table(order);
if (!address) {
DRM_ERROR("cannot allocate PCI GART page!\n");
goto done;
@@ -160,11 +156,13 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
}
bus_address = pci_map_single(dev->pdev, address,
- ATI_PCIGART_TABLE_PAGES *
- PAGE_SIZE, PCI_DMA_TODEVICE);
+ num_pages * PAGE_SIZE,
+ PCI_DMA_TODEVICE);
if (bus_address == 0) {
DRM_ERROR("unable to map PCIGART pages!\n");
- drm_ati_free_pcigart_table(address);
+ order = drm_order((gart_info->table_size +
+ (PAGE_SIZE-1)) / PAGE_SIZE);
+ drm_ati_free_pcigart_table(address, order);
address = NULL;
goto done;
}
@@ -177,10 +175,11 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
pci_gart = (u32 *) address;
- pages = (entry->pages <= ATI_MAX_PCIGART_PAGES)
- ? entry->pages : ATI_MAX_PCIGART_PAGES;
+ max_pages = (gart_info->table_size / sizeof(u32));
+ pages = (entry->pages <= max_pages)
+ ? entry->pages : max_pages;
- memset(pci_gart, 0, ATI_MAX_PCIGART_PAGES * sizeof(u32));
+ memset(pci_gart, 0, max_pages * sizeof(u32));
for (i = 0; i < pages; i++) {
/* we need to support large memory configurations */
@@ -198,10 +197,18 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
page_base = (u32) entry->busaddr[i];
for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
- if (gart_info->is_pcie)
+ switch(gart_info->gart_reg_if) {
+ case DRM_ATI_GART_IGP:
+ *pci_gart = cpu_to_le32((page_base) | 0xc);
+ break;
+ case DRM_ATI_GART_PCIE:
*pci_gart = cpu_to_le32((page_base >> 8) | 0xc);
- else
+ break;
+ default:
+ case DRM_ATI_GART_PCI:
*pci_gart = cpu_to_le32(page_base);
+ break;
+ }
pci_gart++;
page_base += ATI_PCIGART_PAGE_SIZE;
}
@@ -220,5 +227,4 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
gart_info->bus_addr = bus_address;
return ret;
}
-
EXPORT_SYMBOL(drm_ati_pcigart_init);
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 8db9041e306..089198491f1 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -654,11 +654,13 @@ typedef struct drm_set_version {
/**
* Device specific ioctls should only be in their respective headers
- * The device specific ioctl range is from 0x40 to 0x79.
+ * The device specific ioctl range is from 0x40 to 0x99.
+ * Generic IOCTLS restart at 0xA0.
*
* \sa drmCommandNone(), drmCommandRead(), drmCommandWrite(), and
* drmCommandReadWrite().
*/
#define DRM_COMMAND_BASE 0x40
+#define DRM_COMMAND_END 0xA0
#endif
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 85d99e21e18..d494315752a 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -414,6 +414,10 @@ typedef struct drm_lock_data {
struct file *filp; /**< File descr of lock holder (0=kernel) */
wait_queue_head_t lock_queue; /**< Queue of blocked processes */
unsigned long lock_time; /**< Time of last lock in jiffies */
+ spinlock_t spinlock;
+ uint32_t kernel_waiters;
+ uint32_t user_waiters;
+ int idle_has_lock;
} drm_lock_data_t;
/**
@@ -515,12 +519,17 @@ typedef struct drm_vbl_sig {
#define DRM_ATI_GART_MAIN 1
#define DRM_ATI_GART_FB 2
+#define DRM_ATI_GART_PCI 1
+#define DRM_ATI_GART_PCIE 2
+#define DRM_ATI_GART_IGP 3
+
typedef struct ati_pcigart_info {
int gart_table_location;
- int is_pcie;
+ int gart_reg_if;
void *addr;
dma_addr_t bus_addr;
drm_local_map_t mapping;
+ int table_size;
} drm_ati_pcigart_info;
/*
@@ -590,6 +599,8 @@ struct drm_driver {
void (*reclaim_buffers) (struct drm_device * dev, struct file * filp);
void (*reclaim_buffers_locked) (struct drm_device *dev,
struct file *filp);
+ void (*reclaim_buffers_idlelocked) (struct drm_device *dev,
+ struct file * filp);
unsigned long (*get_map_ofs) (drm_map_t * map);
unsigned long (*get_reg_ofs) (struct drm_device * dev);
void (*set_version) (struct drm_device * dev, drm_set_version_t * sv);
@@ -764,7 +775,7 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
}
#ifdef __alpha__
-#define drm_get_pci_domain(dev) dev->hose->bus->number
+#define drm_get_pci_domain(dev) dev->hose->index
#else
#define drm_get_pci_domain(dev) 0
#endif
@@ -915,9 +926,18 @@ extern int drm_lock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_unlock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context);
-extern int drm_lock_free(drm_device_t * dev,
- __volatile__ unsigned int *lock, unsigned int context);
+extern int drm_lock_take(drm_lock_data_t *lock_data, unsigned int context);
+extern int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context);
+extern void drm_idlelock_take(drm_lock_data_t *lock_data);
+extern void drm_idlelock_release(drm_lock_data_t *lock_data);
+
+/*
+ * These are exported to drivers so that they can implement fencing using
+ * DMA quiscent + idle. DMA quiescent usually requires the hardware lock.
+ */
+
+extern int drm_i_have_hw_lock(struct file *filp);
+extern int drm_kernel_take_hw_lock(struct file *filp);
/* Buffer management support (drm_bufs.h) */
extern int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request);
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index a6828cc14e5..c11345856ff 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -57,7 +57,8 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
list_for_each(list, &dev->maplist->head) {
drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
if (entry->map && map->type == entry->map->type &&
- entry->map->offset == map->offset) {
+ ((entry->map->offset == map->offset) ||
+ (map->type == _DRM_SHM && map->flags==_DRM_CONTAINS_LOCK))) {
return entry;
}
}
@@ -180,8 +181,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
if (map->type == _DRM_REGISTERS)
map->handle = ioremap(map->offset, map->size);
break;
-
case _DRM_SHM:
+ list = drm_find_matching_map(dev, map);
+ if (list != NULL) {
+ if(list->map->size != map->size) {
+ DRM_DEBUG("Matching maps of type %d with "
+ "mismatched sizes, (%ld vs %ld)\n",
+ map->type, map->size, list->map->size);
+ list->map->size = map->size;
+ }
+
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ *maplist = list;
+ return 0;
+ }
map->handle = vmalloc_user(map->size);
DRM_DEBUG("%lu %d %p\n",
map->size, drm_order(map->size), map->handle);
@@ -200,15 +213,45 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
dev->sigdata.lock = dev->lock.hw_lock = map->handle; /* Pointer to lock */
}
break;
- case _DRM_AGP:
- if (drm_core_has_AGP(dev)) {
+ case _DRM_AGP: {
+ drm_agp_mem_t *entry;
+ int valid = 0;
+
+ if (!drm_core_has_AGP(dev)) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EINVAL;
+ }
#ifdef __alpha__
- map->offset += dev->hose->mem_space->start;
+ map->offset += dev->hose->mem_space->start;
#endif
- map->offset += dev->agp->base;
- map->mtrr = dev->agp->agp_mtrr; /* for getmap */
+ /* Note: dev->agp->base may actually be 0 when the DRM
+ * is not in control of AGP space. But if user space is
+ * it should already have added the AGP base itself.
+ */
+ map->offset += dev->agp->base;
+ map->mtrr = dev->agp->agp_mtrr; /* for getmap */
+
+ /* This assumes the DRM is in total control of AGP space.
+ * It's not always the case as AGP can be in the control
+ * of user space (i.e. i810 driver). So this loop will get
+ * skipped and we double check that dev->agp->memory is
+ * actually set as well as being invalid before EPERM'ing
+ */
+ for (entry = dev->agp->memory; entry; entry = entry->next) {
+ if ((map->offset >= entry->bound) &&
+ (map->offset + map->size <= entry->bound + entry->pages * PAGE_SIZE)) {
+ valid = 1;
+ break;
+ }
}
+ if (dev->agp->memory && !valid) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ return -EPERM;
+ }
+ DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);
+
break;
+ }
case _DRM_SCATTER_GATHER:
if (!dev->sg) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
@@ -267,7 +310,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
*maplist = list;
return 0;
-}
+ }
int drm_addmap(drm_device_t * dev, unsigned int offset,
unsigned int size, drm_map_type_t type,
@@ -519,6 +562,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
{
drm_device_dma_t *dma = dev->dma;
drm_buf_entry_t *entry;
+ drm_agp_mem_t *agp_entry;
drm_buf_t *buf;
unsigned long offset;
unsigned long agp_offset;
@@ -529,7 +573,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
int page_order;
int total;
int byte_count;
- int i;
+ int i, valid;
drm_buf_t **temp_buflist;
if (!dma)
@@ -560,6 +604,19 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
if (dev->queue_count)
return -EBUSY; /* Not while in use */
+ /* Make sure buffers are located in AGP memory that we own */
+ valid = 0;
+ for (agp_entry = dev->agp->memory; agp_entry; agp_entry = agp_entry->next) {
+ if ((agp_offset >= agp_entry->bound) &&
+ (agp_offset + total * count <= agp_entry->bound + agp_entry->pages * PAGE_SIZE)) {
+ valid = 1;
+ break;
+ }
+ }
+ if (dev->agp->memory && !valid) {
+ DRM_DEBUG("zone invalid\n");
+ return -EINVAL;
+ }
spin_lock(&dev->count_lock);
if (dev->buf_use) {
spin_unlock(&dev->count_lock);
diff --git a/drivers/char/drm/drm_dma.c b/drivers/char/drm/drm_dma.c
index 892db709698..32ed19c9ec1 100644
--- a/drivers/char/drm/drm_dma.c
+++ b/drivers/char/drm/drm_dma.c
@@ -65,7 +65,7 @@ int drm_dma_setup(drm_device_t * dev)
* \param dev DRM device.
*
* Free all pages associated with DMA buffers, the buffers and pages lists, and
- * finally the the drm_device::dma structure itself.
+ * finally the drm_device::dma structure itself.
*/
void drm_dma_takedown(drm_device_t * dev)
{
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index f5b9b2480c1..8e77b7ed0f4 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -15,8 +15,6 @@
* #define DRIVER_DESC "Matrox G200/G400"
* #define DRIVER_DATE "20001127"
*
- * #define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( mga_ioctls )
- *
* #define drm_x mga_##x
* \endcode
*/
@@ -120,7 +118,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_UPDATE_DRAW)] = {drm_update_drawable_info, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
};
-#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
+#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
/**
* Take down the DRM device.
@@ -496,11 +494,14 @@ int drm_ioctl(struct inode *inode, struct file *filp,
(long)old_encode_dev(priv->head->device),
priv->authenticated);
- if (nr < DRIVER_IOCTL_COUNT)
- ioctl = &drm_ioctls[nr];
- else if ((nr >= DRM_COMMAND_BASE)
- && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
+ if ((nr >= DRM_CORE_IOCTL_COUNT) &&
+ ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
+ goto err_i1;
+ if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) &&
+ (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls))
ioctl = &dev->driver->ioctls[nr - DRM_COMMAND_BASE];
+ else if ((nr >= DRM_COMMAND_END) || (nr < DRM_COMMAND_BASE))
+ ioctl = &drm_ioctls[nr];
else
goto err_i1;
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 898f47dafec..3b159cab3bc 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -46,6 +46,7 @@ static int drm_setup(drm_device_t * dev)
drm_local_map_t *map;
int i;
int ret;
+ u32 sareapage;
if (dev->driver->firstopen) {
ret = dev->driver->firstopen(dev);
@@ -56,7 +57,8 @@ static int drm_setup(drm_device_t * dev)
dev->magicfree.next = NULL;
/* prebuild the SAREA */
- i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
+ sareapage = max_t(unsigned, SAREA_MAX, PAGE_SIZE);
+ i = drm_addmap(dev, 0, sareapage, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
if (i != 0)
return i;
@@ -84,7 +86,7 @@ static int drm_setup(drm_device_t * dev)
INIT_LIST_HEAD(&dev->ctxlist->head);
dev->vmalist = NULL;
- dev->sigdata.lock = dev->lock.hw_lock = NULL;
+ dev->sigdata.lock = NULL;
init_waitqueue_head(&dev->lock.lock_queue);
dev->queue_count = 0;
dev->queue_reserved = 0;
@@ -354,58 +356,56 @@ int drm_release(struct inode *inode, struct file *filp)
current->pid, (long)old_encode_dev(priv->head->device),
dev->open_count);
- if (priv->lock_count && dev->lock.hw_lock &&
- _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
- dev->lock.filp == filp) {
- DRM_DEBUG("File %p released, freeing lock for context %d\n",
- filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-
- if (dev->driver->reclaim_buffers_locked)
+ if (dev->driver->reclaim_buffers_locked && dev->lock.hw_lock) {
+ if (drm_i_have_hw_lock(filp)) {
dev->driver->reclaim_buffers_locked(dev, filp);
-
- drm_lock_free(dev, &dev->lock.hw_lock->lock,
- _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-
- /* FIXME: may require heavy-handed reset of
- hardware at this point, possibly
- processed via a callback to the X
- server. */
- } else if (dev->driver->reclaim_buffers_locked && priv->lock_count
- && dev->lock.hw_lock) {
- /* The lock is required to reclaim buffers */
- DECLARE_WAITQUEUE(entry, current);
-
- add_wait_queue(&dev->lock.lock_queue, &entry);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- if (!dev->lock.hw_lock) {
- /* Device has been unregistered */
- retcode = -EINTR;
- break;
+ } else {
+ unsigned long _end=jiffies + 3*DRM_HZ;
+ int locked = 0;
+
+ drm_idlelock_take(&dev->lock);
+
+ /*
+ * Wait for a while.
+ */
+
+ do{
+ spin_lock(&dev->lock.spinlock);
+ locked = dev->lock.idle_has_lock;
+ spin_unlock(&dev->lock.spinlock);
+ if (locked)
+ break;
+ schedule();
+ } while (!time_after_eq(jiffies, _end));
+
+ if (!locked) {
+ DRM_ERROR("reclaim_buffers_locked() deadlock. Please rework this\n"
+ "\tdriver to use reclaim_buffers_idlelocked() instead.\n"
+ "\tI will go on reclaiming the buffers anyway.\n");
}
- if (drm_lock_take(&dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- dev->lock.filp = filp;
- dev->lock.lock_time = jiffies;
- atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
- break; /* Got lock */
- }
- /* Contention */
- schedule();
- if (signal_pending(current)) {
- retcode = -ERESTARTSYS;
- break;
- }
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&dev->lock.lock_queue, &entry);
- if (!retcode) {
+
dev->driver->reclaim_buffers_locked(dev, filp);
- drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT);
+ drm_idlelock_release(&dev->lock);
}
}
+ if (dev->driver->reclaim_buffers_idlelocked && dev->lock.hw_lock) {
+
+ drm_idlelock_take(&dev->lock);
+ dev->driver->reclaim_buffers_idlelocked(dev, filp);
+ drm_idlelock_release(&dev->lock);
+
+ }
+
+ if (drm_i_have_hw_lock(filp)) {
+ DRM_DEBUG("File %p released, freeing lock for context %d\n",
+ filp, _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+
+ drm_lock_free(&dev->lock,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+ }
+
+
if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) &&
!dev->driver->reclaim_buffers_locked) {
dev->driver->reclaim_buffers(dev, filp);
diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c
index a0b2d6802ae..31acb621dcc 100644
--- a/drivers/char/drm/drm_hashtab.c
+++ b/drivers/char/drm/drm_hashtab.c
@@ -43,7 +43,16 @@ int drm_ht_create(drm_open_hash_t *ht, unsigned int order)
ht->size = 1 << order;
ht->order = order;
ht->fill = 0;
- ht->table = vmalloc(ht->size*sizeof(*ht->table));
+ ht->table = NULL;
+ ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE);
+ if (!ht->use_vmalloc) {
+ ht->table = drm_calloc(ht->size, sizeof(*ht->table),
+ DRM_MEM_HASHTAB);
+ }
+ if (!ht->table) {
+ ht->use_vmalloc = 1;
+ ht->table = vmalloc(ht->size*sizeof(*ht->table));
+ }
if (!ht->table) {
DRM_ERROR("Out of memory for hash table\n");
return -ENOMEM;
@@ -183,7 +192,11 @@ int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item)
void drm_ht_remove(drm_open_hash_t *ht)
{
if (ht->table) {
- vfree(ht->table);
+ if (ht->use_vmalloc)
+ vfree(ht->table);
+ else
+ drm_free(ht->table, ht->size * sizeof(*ht->table),
+ DRM_MEM_HASHTAB);
ht->table = NULL;
}
}
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h
index 40afec05bff..613091c970a 100644
--- a/drivers/char/drm/drm_hashtab.h
+++ b/drivers/char/drm/drm_hashtab.h
@@ -47,6 +47,7 @@ typedef struct drm_open_hash{
unsigned int order;
unsigned int fill;
struct hlist_head *table;
+ int use_vmalloc;
} drm_open_hash_t;
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 9d00c51fe2c..2e75331fd83 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -424,7 +424,7 @@ static void drm_locked_tasklet_func(unsigned long data)
spin_lock_irqsave(&dev->tasklet_lock, irqflags);
if (!dev->locked_tasklet_func ||
- !drm_lock_take(&dev->lock.hw_lock->lock,
+ !drm_lock_take(&dev->lock,
DRM_KERNEL_CONTEXT)) {
spin_unlock_irqrestore(&dev->tasklet_lock, irqflags);
return;
@@ -435,7 +435,7 @@ static void drm_locked_tasklet_func(unsigned long data)
dev->locked_tasklet_func(dev);
- drm_lock_free(dev, &dev->lock.hw_lock->lock,
+ drm_lock_free(&dev->lock,
DRM_KERNEL_CONTEXT);
dev->locked_tasklet_func = NULL;
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index e9993ba461a..befd1af19df 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -35,9 +35,6 @@
#include "drmP.h"
-static int drm_lock_transfer(drm_device_t * dev,
- __volatile__ unsigned int *lock,
- unsigned int context);
static int drm_notifier(void *priv);
/**
@@ -80,6 +77,9 @@ int drm_lock(struct inode *inode, struct file *filp,
return -EINVAL;
add_wait_queue(&dev->lock.lock_queue, &entry);
+ spin_lock(&dev->lock.spinlock);
+ dev->lock.user_waiters++;
+ spin_unlock(&dev->lock.spinlock);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
if (!dev->lock.hw_lock) {
@@ -87,7 +87,7 @@ int drm_lock(struct inode *inode, struct file *filp,
ret = -EINTR;
break;
}
- if (drm_lock_take(&dev->lock.hw_lock->lock, lock.context)) {
+ if (drm_lock_take(&dev->lock, lock.context)) {
dev->lock.filp = filp;
dev->lock.lock_time = jiffies;
atomic_inc(&dev->counts[_DRM_STAT_LOCKS]);
@@ -101,12 +101,14 @@ int drm_lock(struct inode *inode, struct file *filp,
break;
}
}
+ spin_lock(&dev->lock.spinlock);
+ dev->lock.user_waiters--;
+ spin_unlock(&dev->lock.spinlock);
__set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->lock.lock_queue, &entry);
- DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
- if (ret)
- return ret;
+ DRM_DEBUG( "%d %s\n", lock.context, ret ? "interrupted" : "has lock" );
+ if (ret) return ret;
sigemptyset(&dev->sigmask);
sigaddset(&dev->sigmask, SIGSTOP);
@@ -127,14 +129,12 @@ int drm_lock(struct inode *inode, struct file *filp,
}
}
- /* dev->driver->kernel_context_switch isn't used by any of the x86
- * drivers but is used by the Sparc driver.
- */
if (dev->driver->kernel_context_switch &&
dev->last_context != lock.context) {
dev->driver->kernel_context_switch(dev, dev->last_context,
lock.context);
}
+
return 0;
}
@@ -184,12 +184,8 @@ int drm_unlock(struct inode *inode, struct file *filp,
if (dev->driver->kernel_context_switch_unlock)
dev->driver->kernel_context_switch_unlock(dev);
else {
- drm_lock_transfer(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT);
-
- if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- DRM_ERROR("\n");
+ if (drm_lock_free(&dev->lock,lock.context)) {
+ /* FIXME: Should really bail out here. */
}
}
@@ -206,18 +202,26 @@ int drm_unlock(struct inode *inode, struct file *filp,
*
* Attempt to mark the lock as held by the given context, via the \p cmpxchg instruction.
*/
-int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
+int drm_lock_take(drm_lock_data_t *lock_data,
+ unsigned int context)
{
unsigned int old, new, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
+ spin_lock(&lock_data->spinlock);
do {
old = *lock;
if (old & _DRM_LOCK_HELD)
new = old | _DRM_LOCK_CONT;
- else
- new = context | _DRM_LOCK_HELD;
+ else {
+ new = context | _DRM_LOCK_HELD |
+ ((lock_data->user_waiters + lock_data->kernel_waiters > 1) ?
+ _DRM_LOCK_CONT : 0);
+ }
prev = cmpxchg(lock, old, new);
} while (prev != old);
+ spin_unlock(&lock_data->spinlock);
+
if (_DRM_LOCKING_CONTEXT(old) == context) {
if (old & _DRM_LOCK_HELD) {
if (context != DRM_KERNEL_CONTEXT) {
@@ -227,7 +231,8 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
return 0;
}
}
- if (new == (context | _DRM_LOCK_HELD)) {
+
+ if ((_DRM_LOCKING_CONTEXT(new)) == context && (new & _DRM_LOCK_HELD)) {
/* Have lock */
return 1;
}
@@ -246,13 +251,13 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
* Resets the lock file pointer.
* Marks the lock as held by the given context, via the \p cmpxchg instruction.
*/
-static int drm_lock_transfer(drm_device_t * dev,
- __volatile__ unsigned int *lock,
+static int drm_lock_transfer(drm_lock_data_t *lock_data,
unsigned int context)
{
unsigned int old, new, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
- dev->lock.filp = NULL;
+ lock_data->filp = NULL;
do {
old = *lock;
new = context | _DRM_LOCK_HELD;
@@ -272,23 +277,32 @@ static int drm_lock_transfer(drm_device_t * dev,
* Marks the lock as not held, via the \p cmpxchg instruction. Wakes any task
* waiting on the lock queue.
*/
-int drm_lock_free(drm_device_t * dev,
- __volatile__ unsigned int *lock, unsigned int context)
+int drm_lock_free(drm_lock_data_t *lock_data, unsigned int context)
{
unsigned int old, new, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
+
+ spin_lock(&lock_data->spinlock);
+ if (lock_data->kernel_waiters != 0) {
+ drm_lock_transfer(lock_data, 0);
+ lock_data->idle_has_lock = 1;
+ spin_unlock(&lock_data->spinlock);
+ return 1;
+ }
+ spin_unlock(&lock_data->spinlock);
- dev->lock.filp = NULL;
do {
old = *lock;
- new = 0;
+ new = _DRM_LOCKING_CONTEXT(old);
prev = cmpxchg(lock, old, new);
} while (prev != old);
+
if (_DRM_LOCK_IS_HELD(old) && _DRM_LOCKING_CONTEXT(old) != context) {
DRM_ERROR("%d freed heavyweight lock held by %d\n",
context, _DRM_LOCKING_CONTEXT(old));
return 1;
}
- wake_up_interruptible(&dev->lock.lock_queue);
+ wake_up_interruptible(&lock_data->lock_queue);
return 0;
}
@@ -322,3 +336,67 @@ static int drm_notifier(void *priv)
} while (prev != old);
return 0;
}
+
+/**
+ * This function returns immediately and takes the hw lock
+ * with the kernel context if it is free, otherwise it gets the highest priority when and if
+ * it is eventually released.
+ *
+ * This guarantees that the kernel will _eventually_ have the lock _unless_ it is held
+ * by a blocked process. (In the latter case an explicit wait for the hardware lock would cause
+ * a deadlock, which is why the "idlelock" was invented).
+ *
+ * This should be sufficient to wait for GPU idle without
+ * having to worry about starvation.
+ */
+
+void drm_idlelock_take(drm_lock_data_t *lock_data)
+{
+ int ret = 0;
+
+ spin_lock(&lock_data->spinlock);
+ lock_data->kernel_waiters++;
+ if (!lock_data->idle_has_lock) {
+
+ spin_unlock(&lock_data->spinlock);
+ ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT);
+ spin_lock(&lock_data->spinlock);
+
+ if (ret == 1)
+ lock_data->idle_has_lock = 1;
+ }
+ spin_unlock(&lock_data->spinlock);
+}
+EXPORT_SYMBOL(drm_idlelock_take);
+
+void drm_idlelock_release(drm_lock_data_t *lock_data)
+{
+ unsigned int old, prev;
+ volatile unsigned int *lock = &lock_data->hw_lock->lock;
+
+ spin_lock(&lock_data->spinlock);
+ if (--lock_data->kernel_waiters == 0) {
+ if (lock_data->idle_has_lock) {
+ do {
+ old = *lock;
+ prev = cmpxchg(lock, old, DRM_KERNEL_CONTEXT);
+ } while (prev != old);
+ wake_up_interruptible(&lock_data->lock_queue);
+ lock_data->idle_has_lock = 0;
+ }
+ }
+ spin_unlock(&lock_data->spinlock);
+}
+EXPORT_SYMBOL(drm_idlelock_release);
+
+
+int drm_i_have_hw_lock(struct file *filp)
+{
+ DRM_DEVICE;
+
+ return (priv->lock_count && dev->lock.hw_lock &&
+ _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) &&
+ dev->lock.filp == filp);
+}
+
+EXPORT_SYMBOL(drm_i_have_hw_lock);
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
index 9b46b85027d..2ec1d9f2626 100644
--- a/drivers/char/drm/drm_mm.c
+++ b/drivers/char/drm/drm_mm.c
@@ -274,7 +274,6 @@ int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
return drm_mm_create_tail_node(mm, start, size);
}
-EXPORT_SYMBOL(drm_mm_init);
void drm_mm_takedown(drm_mm_t * mm)
{
@@ -295,4 +294,3 @@ void drm_mm_takedown(drm_mm_t * mm)
drm_free(entry, sizeof(*entry), DRM_MEM_MM);
}
-EXPORT_SYMBOL(drm_mm_takedown);
diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h
index 2908b72daa6..0fe7b449792 100644
--- a/drivers/char/drm/drm_os_linux.h
+++ b/drivers/char/drm/drm_os_linux.h
@@ -70,9 +70,6 @@ static __inline__ int mtrr_del(int reg, unsigned long base, unsigned long size)
#endif
-/** Task queue handler arguments */
-#define DRM_TASKQUEUE_ARGS void *arg
-
/** For data going into the kernel through the ioctl argument */
#define DRM_COPY_FROM_USER_IOCTL(arg1, arg2, arg3) \
if ( copy_from_user(&arg1, arg2, arg3) ) \
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index ad54b845978..31cdde83713 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -102,6 +102,7 @@
{0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
{0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
@@ -230,10 +231,10 @@
{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
- {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
+ {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
{0, 0, 0}
#define i810_PCI_IDS \
@@ -296,5 +297,6 @@
{0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x2a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0, 0, 0}
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 7fd0da71214..b204498d1a2 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -72,7 +72,7 @@ static struct drm_proc_list {
#endif
};
-#define DRM_PROC_ENTRIES (sizeof(drm_proc_list)/sizeof(drm_proc_list[0]))
+#define DRM_PROC_ENTRIES ARRAY_SIZE(drm_proc_list)
/**
* Initialize the DRI proc filesystem for a device.
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 120d10256fe..19408adcc77 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -62,6 +62,7 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
spin_lock_init(&dev->count_lock);
spin_lock_init(&dev->drw_lock);
spin_lock_init(&dev->tasklet_lock);
+ spin_lock_init(&dev->lock.spinlock);
init_timer(&dev->timer);
mutex_init(&dev->struct_mutex);
mutex_init(&dev->ctxlist_mutex);
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index 54a63284895..b5c5b9fa84c 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -41,6 +41,30 @@
static void drm_vm_open(struct vm_area_struct *vma);
static void drm_vm_close(struct vm_area_struct *vma);
+static pgprot_t drm_io_prot(uint32_t map_type, struct vm_area_struct *vma)
+{
+ pgprot_t tmp = vm_get_page_prot(vma->vm_flags);
+
+#if defined(__i386__) || defined(__x86_64__)
+ if (boot_cpu_data.x86 > 3 && map_type != _DRM_AGP) {
+ pgprot_val(tmp) |= _PAGE_PCD;
+ pgprot_val(tmp) &= ~_PAGE_PWT;
+ }
+#elif defined(__powerpc__)
+ pgprot_val(tmp) |= _PAGE_NO_CACHE;
+ if (map_type == _DRM_REGISTERS)
+ pgprot_val(tmp) |= _PAGE_GUARDED;
+#endif
+#if defined(__ia64__)
+ if (efi_range_is_wc(vma->vm_start, vma->vm_end -
+ vma->vm_start))
+ tmp = pgprot_writecombine(tmp);
+ else
+ tmp = pgprot_noncached(tmp);
+#endif
+ return tmp;
+}
+
/**
* \c nopage method for AGP virtual memory.
*
@@ -133,7 +157,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
* \param address access address.
* \return pointer to the page structure.
*
- * Get the the mapping, find the real physical page to map, get the page, and
+ * Get the mapping, find the real physical page to map, get the page, and
* return it.
*/
static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
@@ -151,8 +175,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
offset = address - vma->vm_start;
i = (unsigned long)map->handle + offset;
- page = (map->type == _DRM_CONSISTENT) ?
- virt_to_page((void *)i) : vmalloc_to_page((void *)i);
+ page = vmalloc_to_page((void *)i);
if (!page)
return NOPAGE_SIGBUS;
get_page(page);
@@ -389,7 +412,7 @@ static struct vm_operations_struct drm_vm_sg_ops = {
* Create a new drm_vma_entry structure as the \p vma private data entry and
* add it to drm_device::vmalist.
*/
-static void drm_vm_open(struct vm_area_struct *vma)
+static void drm_vm_open_locked(struct vm_area_struct *vma)
{
drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->head->dev;
@@ -401,15 +424,23 @@ static void drm_vm_open(struct vm_area_struct *vma)
vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
if (vma_entry) {
- mutex_lock(&dev->struct_mutex);
vma_entry->vma = vma;
vma_entry->next = dev->vmalist;
vma_entry->pid = current->pid;
dev->vmalist = vma_entry;
- mutex_unlock(&dev->struct_mutex);
}
}
+static void drm_vm_open(struct vm_area_struct *vma)
+{
+ drm_file_t *priv = vma->vm_file->private_data;
+ drm_device_t *dev = priv->head->dev;
+
+ mutex_lock(&dev->struct_mutex);
+ drm_vm_open_locked(vma);
+ mutex_unlock(&dev->struct_mutex);
+}
+
/**
* \c close method for all virtual memory types.
*
@@ -460,7 +491,6 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
drm_device_dma_t *dma;
unsigned long length = vma->vm_end - vma->vm_start;
- lock_kernel();
dev = priv->head->dev;
dma = dev->dma;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
@@ -468,10 +498,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
/* Length must match exact page count */
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
- unlock_kernel();
return -EINVAL;
}
- unlock_kernel();
if (!capable(CAP_SYS_ADMIN) &&
(dma->flags & _DRM_DMA_USE_PCI_RO)) {
@@ -494,7 +522,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_file = filp; /* Needed for drm_vm_open() */
- drm_vm_open(vma);
+ drm_vm_open_locked(vma);
return 0;
}
@@ -529,7 +557,7 @@ EXPORT_SYMBOL(drm_core_get_reg_ofs);
* according to the mapping type and remaps the pages. Finally sets the file
* pointer and calls vm_open().
*/
-int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
@@ -565,7 +593,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
return -EPERM;
/* Check for valid size. */
- if (map->size != vma->vm_end - vma->vm_start)
+ if (map->size < vma->vm_end - vma->vm_start)
return -EINVAL;
if (!capable(CAP_SYS_ADMIN) && (map->flags & _DRM_READ_ONLY)) {
@@ -600,37 +628,16 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
/* fall through to _DRM_FRAME_BUFFER... */
case _DRM_FRAME_BUFFER:
case _DRM_REGISTERS:
-#if defined(__i386__) || defined(__x86_64__)
- if (boot_cpu_data.x86 > 3 && map->type != _DRM_AGP) {
- pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
- pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
- }
-#elif defined(__powerpc__)
- pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
- if (map->type == _DRM_REGISTERS)
- pgprot_val(vma->vm_page_prot) |= _PAGE_GUARDED;
-#endif
- vma->vm_flags |= VM_IO; /* not in core dump */
-#if defined(__ia64__)
- if (efi_range_is_wc(vma->vm_start, vma->vm_end - vma->vm_start))
- vma->vm_page_prot =
- pgprot_writecombine(vma->vm_page_prot);
- else
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-#endif
offset = dev->driver->get_reg_ofs(dev);
+ vma->vm_flags |= VM_IO; /* not in core dump */
+ vma->vm_page_prot = drm_io_prot(map->type, vma);
#ifdef __sparc__
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+#endif
if (io_remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
-#else
- if (io_remap_pfn_range(vma, vma->vm_start,
- (map->offset + offset) >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot))
-#endif
return -EAGAIN;
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
" offset = 0x%lx\n",
@@ -638,10 +645,15 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_start, vma->vm_end, map->offset + offset);
vma->vm_ops = &drm_vm_ops;
break;
- case _DRM_SHM:
case _DRM_CONSISTENT:
- /* Consistent memory is really like shared memory. It's only
- * allocate in a different way */
+ /* Consistent memory is really like shared memory. But
+ * it's allocated in a different way, so avoid nopage */
+ if (remap_pfn_range(vma, vma->vm_start,
+ page_to_pfn(virt_to_page(map->handle)),
+ vma->vm_end - vma->vm_start, vma->vm_page_prot))
+ return -EAGAIN;
+ /* fall through to _DRM_SHM */
+ case _DRM_SHM:
vma->vm_ops = &drm_vm_shm_ops;
vma->vm_private_data = (void *)map;
/* Don't let this area swap. Change when
@@ -659,8 +671,20 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_file = filp; /* Needed for drm_vm_open() */
- drm_vm_open(vma);
+ drm_vm_open_locked(vma);
return 0;
}
+int drm_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ int ret;
+
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_mmap_locked(filp, vma);
+ mutex_unlock(&dev->struct_mutex);
+
+ return ret;
+}
EXPORT_SYMBOL(drm_mmap);
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 9354ce3b009..1ba15d9a171 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -34,7 +34,8 @@
#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
dev->pci_device == 0x2982 || \
dev->pci_device == 0x2992 || \
- dev->pci_device == 0x29A2)
+ dev->pci_device == 0x29A2 || \
+ dev->pci_device == 0x2A02)
/* Really want an OS-independent resettable timer. Would like to have
* this loop run for (eg) 3 sec, but have the timer reset every time
diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c
index db5a60450e6..1014602c43a 100644
--- a/drivers/char/drm/r128_cce.c
+++ b/drivers/char/drm/r128_cce.c
@@ -560,9 +560,10 @@ static int r128_do_init_cce(drm_device_t * dev, drm_r128_init_t * init)
if (dev_priv->is_pci) {
#endif
dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
+ dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;
dev_priv->gart_info.addr = NULL;
dev_priv->gart_info.bus_addr = 0;
- dev_priv->gart_info.is_pcie = 0;
+ dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
if (!drm_ati_pcigart_init(dev, &dev_priv->gart_info)) {
DRM_ERROR("failed to init PCI GART!\n");
dev->dev_private = (void *)dev_priv;
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index f1efb49de8d..9086835686d 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -383,6 +383,8 @@ extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
#define R128_PERFORMANCE_BOXES 0
+#define R128_PCIGART_TABLE_SIZE 32768
+
#define R128_READ(reg) DRM_READ32( dev_priv->mmio, (reg) )
#define R128_WRITE(reg,val) DRM_WRITE32( dev_priv->mmio, (reg), (val) )
#define R128_READ8(reg) DRM_READ8( dev_priv->mmio, (reg) )
diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h
index a881f96c983..ecda760ae8c 100644
--- a/drivers/char/drm/r300_reg.h
+++ b/drivers/char/drm/r300_reg.h
@@ -293,7 +293,7 @@ I am fairly certain that they are correct unless stated otherwise in comments.
# define R300_PVS_CNTL_1_PROGRAM_START_SHIFT 0
# define R300_PVS_CNTL_1_POS_END_SHIFT 10
# define R300_PVS_CNTL_1_PROGRAM_END_SHIFT 20
-/* Addresses are relative the the vertex program parameters area. */
+/* Addresses are relative to the vertex program parameters area. */
#define R300_VAP_PVS_CNTL_2 0x22D4
# define R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT 0
# define R300_PVS_CNTL_2_PARAM_COUNT_SHIFT 16
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 5ed96568829..68338389d83 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -830,6 +830,15 @@ static int RADEON_READ_PCIE(drm_radeon_private_t *dev_priv, int addr)
return RADEON_READ(RADEON_PCIE_DATA);
}
+static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr)
+{
+ u32 ret;
+ RADEON_WRITE(RADEON_IGPGART_INDEX, addr & 0x7f);
+ ret = RADEON_READ(RADEON_IGPGART_DATA);
+ RADEON_WRITE(RADEON_IGPGART_INDEX, 0x7f);
+ return ret;
+}
+
#if RADEON_FIFO_DEBUG
static void radeon_status(drm_radeon_private_t * dev_priv)
{
@@ -1267,7 +1276,44 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
}
}
-/* Enable or disable PCI-E GART on the chip */
+/* Enable or disable IGP GART on the chip */
+static void radeon_set_igpgart(drm_radeon_private_t * dev_priv, int on)
+{
+ u32 temp, tmp;
+
+ tmp = RADEON_READ(RADEON_AIC_CNTL);
+ if (on) {
+ DRM_DEBUG("programming igpgart %08X %08lX %08X\n",
+ dev_priv->gart_vm_start,
+ (long)dev_priv->gart_info.bus_addr,
+ dev_priv->gart_size);
+
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_18, 0x1000);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, 0x1);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_CTRL, 0x42040800);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_BASE_ADDR,
+ dev_priv->gart_info.bus_addr);
+
+ temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_UNK_39);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_UNK_39, temp);
+
+ RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev_priv->gart_vm_start);
+ dev_priv->gart_size = 32*1024*1024;
+ RADEON_WRITE(RADEON_MC_AGP_LOCATION,
+ (((dev_priv->gart_vm_start - 1 +
+ dev_priv->gart_size) & 0xffff0000) |
+ (dev_priv->gart_vm_start >> 16)));
+
+ temp = RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_ENABLE);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_ENABLE, temp);
+
+ RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x1);
+ RADEON_READ_IGPGART(dev_priv, RADEON_IGPGART_FLUSH);
+ RADEON_WRITE_IGPGART(RADEON_IGPGART_FLUSH, 0x0);
+ }
+}
+
static void radeon_set_pciegart(drm_radeon_private_t * dev_priv, int on)
{
u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
@@ -1302,6 +1348,11 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
{
u32 tmp;
+ if (dev_priv->flags & RADEON_IS_IGPGART) {
+ radeon_set_igpgart(dev_priv, on);
+ return;
+ }
+
if (dev_priv->flags & RADEON_IS_PCIE) {
radeon_set_pciegart(dev_priv, on);
return;
@@ -1560,8 +1611,8 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
if (dev_priv->flags & RADEON_IS_AGP) {
base = dev->agp->base;
/* Check if valid */
- if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
- base < (dev_priv->fb_location + dev_priv->fb_size)) {
+ if ((base + dev_priv->gart_size - 1) >= dev_priv->fb_location &&
+ base < (dev_priv->fb_location + dev_priv->fb_size - 1)) {
DRM_INFO("Can't use AGP base @0x%08lx, won't fit\n",
dev->agp->base);
base = 0;
@@ -1571,8 +1622,8 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
/* If not or if AGP is at 0 (Macs), try to put it elsewhere */
if (base == 0) {
base = dev_priv->fb_location + dev_priv->fb_size;
- if (((base + dev_priv->gart_size) & 0xfffffffful)
- < base)
+ if (base < dev_priv->fb_location ||
+ ((base + dev_priv->gart_size) & 0xfffffffful) < base)
base = dev_priv->fb_location
- dev_priv->gart_size;
}
@@ -1620,20 +1671,22 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
#endif
{
/* if we have an offset set from userspace */
- if (dev_priv->pcigart_offset) {
+ if (dev_priv->pcigart_offset_set) {
dev_priv->gart_info.bus_addr =
dev_priv->pcigart_offset + dev_priv->fb_location;
dev_priv->gart_info.mapping.offset =
dev_priv->gart_info.bus_addr;
dev_priv->gart_info.mapping.size =
- RADEON_PCIGART_TABLE_SIZE;
+ dev_priv->gart_info.table_size;
drm_core_ioremap(&dev_priv->gart_info.mapping, dev);
dev_priv->gart_info.addr =
dev_priv->gart_info.mapping.handle;
- dev_priv->gart_info.is_pcie =
- !!(dev_priv->flags & RADEON_IS_PCIE);
+ if (dev_priv->flags & RADEON_IS_PCIE)
+ dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCIE;
+ else
+ dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
dev_priv->gart_info.gart_table_location =
DRM_ATI_GART_FB;
@@ -1641,6 +1694,10 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
dev_priv->gart_info.addr,
dev_priv->pcigart_offset);
} else {
+ if (dev_priv->flags & RADEON_IS_IGPGART)
+ dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_IGP;
+ else
+ dev_priv->gart_info.gart_reg_if = DRM_ATI_GART_PCI;
dev_priv->gart_info.gart_table_location =
DRM_ATI_GART_MAIN;
dev_priv->gart_info.addr = NULL;
@@ -1714,7 +1771,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev)
if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
{
drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
- dev_priv->gart_info.addr = NULL;
+ dev_priv->gart_info.addr = 0;
}
}
/* only clear to the start of flags */
@@ -2222,6 +2279,8 @@ int radeon_driver_firstopen(struct drm_device *dev)
drm_local_map_t *map;
drm_radeon_private_t *dev_priv = dev->dev_private;
+ dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
+
ret = drm_addmap(dev, drm_get_resource_start(dev, 2),
drm_get_resource_len(dev, 2), _DRM_REGISTERS,
_DRM_READ_ONLY, &dev_priv->mmio);
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
index 8d6350dd536..66c4b6fed04 100644
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -707,6 +707,7 @@ typedef struct drm_radeon_setparam {
#define RADEON_SETPARAM_SWITCH_TILING 2 /* enable/disable color tiling */
#define RADEON_SETPARAM_PCIGART_LOCATION 3 /* PCI Gart Location */
#define RADEON_SETPARAM_NEW_MEMMAP 4 /* Use new memory map */
+#define RADEON_SETPARAM_PCIGART_TABLE_SIZE 5 /* PCI GART Table Size */
/* 1.14: Clients can allocate/free a surface
*/
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 8b105f1460a..54f49ef4bef 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -95,9 +95,11 @@
* 1.24- Add general-purpose packet for manipulating scratch registers (r300)
* 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL,
* new packet type)
+ * 1.26- Add support for variable size PCI(E) gart aperture
+ * 1.27- Add support for IGP GART
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 25
+#define DRIVER_MINOR 27
#define DRIVER_PATCHLEVEL 0
/*
@@ -143,6 +145,7 @@ enum radeon_chip_flags {
RADEON_IS_PCIE = 0x00200000UL,
RADEON_NEW_MEMMAP = 0x00400000UL,
RADEON_IS_PCI = 0x00800000UL,
+ RADEON_IS_IGPGART = 0x01000000UL,
};
#define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \
@@ -240,7 +243,6 @@ typedef struct drm_radeon_private {
int do_boxes;
int page_flipping;
- int current_page;
u32 color_fmt;
unsigned int front_offset;
@@ -280,6 +282,7 @@ typedef struct drm_radeon_private {
struct radeon_virt_surface virt_surfaces[2 * RADEON_MAX_SURFACES];
unsigned long pcigart_offset;
+ unsigned int pcigart_offset_set;
drm_ati_pcigart_info gart_info;
u32 scratch_ages[5];
@@ -432,6 +435,15 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define RADEON_PCIE_TX_GART_END_LO 0x16
#define RADEON_PCIE_TX_GART_END_HI 0x17
+#define RADEON_IGPGART_INDEX 0x168
+#define RADEON_IGPGART_DATA 0x16c
+#define RADEON_IGPGART_UNK_18 0x18
+#define RADEON_IGPGART_CTRL 0x2b
+#define RADEON_IGPGART_BASE_ADDR 0x2c
+#define RADEON_IGPGART_FLUSH 0x2e
+#define RADEON_IGPGART_ENABLE 0x38
+#define RADEON_IGPGART_UNK_39 0x39
+
#define RADEON_MPP_TB_CONFIG 0x01c0
#define RADEON_MEM_CNTL 0x0140
#define RADEON_MEM_SDRAM_MODE_REG 0x0158
@@ -964,6 +976,14 @@ do { \
RADEON_WRITE( RADEON_CLOCK_CNTL_DATA, (val) ); \
} while (0)
+#define RADEON_WRITE_IGPGART( addr, val ) \
+do { \
+ RADEON_WRITE( RADEON_IGPGART_INDEX, \
+ ((addr) & 0x7f) | (1 << 8)); \
+ RADEON_WRITE( RADEON_IGPGART_DATA, (val) ); \
+ RADEON_WRITE( RADEON_IGPGART_INDEX, 0x7f ); \
+} while (0)
+
#define RADEON_WRITE_PCIE( addr, val ) \
do { \
RADEON_WRITE8( RADEON_PCIE_INDEX, \
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 938eccb78cc..98c5f1d3a8e 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -773,7 +773,7 @@ static void radeon_clear_box(drm_radeon_private_t * dev_priv,
RADEON_GMC_SRC_DATATYPE_COLOR |
RADEON_ROP3_P | RADEON_GMC_CLR_CMP_CNTL_DIS);
- if (dev_priv->page_flipping && dev_priv->current_page == 1) {
+ if (dev_priv->sarea_priv->pfCurrentPage == 1) {
OUT_RING(dev_priv->front_pitch_offset);
} else {
OUT_RING(dev_priv->back_pitch_offset);
@@ -861,7 +861,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev,
dev_priv->stats.clears++;
- if (dev_priv->page_flipping && dev_priv->current_page == 1) {
+ if (dev_priv->sarea_priv->pfCurrentPage == 1) {
unsigned int tmp = flags;
flags &= ~(RADEON_FRONT | RADEON_BACK);
@@ -1382,7 +1382,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev)
/* Make this work even if front & back are flipped:
*/
OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
- if (dev_priv->current_page == 0) {
+ if (dev_priv->sarea_priv->pfCurrentPage == 0) {
OUT_RING(dev_priv->back_pitch_offset);
OUT_RING(dev_priv->front_pitch_offset);
} else {
@@ -1416,12 +1416,12 @@ static void radeon_cp_dispatch_flip(drm_device_t * dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
drm_sarea_t *sarea = (drm_sarea_t *) dev_priv->sarea->handle;
- int offset = (dev_priv->current_page == 1)
+ int offset = (dev_priv->sarea_priv->pfCurrentPage == 1)
? dev_priv->front_offset : dev_priv->back_offset;
RING_LOCALS;
- DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
+ DRM_DEBUG("%s: pfCurrentPage=%d\n",
__FUNCTION__,
- dev_priv->current_page, dev_priv->sarea_priv->pfCurrentPage);
+ dev_priv->sarea_priv->pfCurrentPage);
/* Do some trivial performance monitoring...
*/
@@ -1449,8 +1449,8 @@ static void radeon_cp_dispatch_flip(drm_device_t * dev)
* performing the swapbuffer ioctl.
*/
dev_priv->sarea_priv->last_frame++;
- dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page =
- 1 - dev_priv->current_page;
+ dev_priv->sarea_priv->pfCurrentPage =
+ 1 - dev_priv->sarea_priv->pfCurrentPage;
BEGIN_RING(2);
@@ -2152,24 +2152,10 @@ static int radeon_do_init_pageflip(drm_device_t * dev)
ADVANCE_RING();
dev_priv->page_flipping = 1;
- dev_priv->current_page = 0;
- dev_priv->sarea_priv->pfCurrentPage = dev_priv->current_page;
- return 0;
-}
-
-/* Called whenever a client dies, from drm_release.
- * NOTE: Lock isn't necessarily held when this is called!
- */
-static int radeon_do_cleanup_pageflip(drm_device_t * dev)
-{
- drm_radeon_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("\n");
-
- if (dev_priv->current_page != 0)
- radeon_cp_dispatch_flip(dev);
+ if (dev_priv->sarea_priv->pfCurrentPage != 1)
+ dev_priv->sarea_priv->pfCurrentPage = 0;
- dev_priv->page_flipping = 0;
return 0;
}
@@ -3145,10 +3131,16 @@ static int radeon_cp_setparam(DRM_IOCTL_ARGS)
break;
case RADEON_SETPARAM_PCIGART_LOCATION:
dev_priv->pcigart_offset = sp.value;
+ dev_priv->pcigart_offset_set = 1;
break;
case RADEON_SETPARAM_NEW_MEMMAP:
dev_priv->new_memmap = sp.value;
break;
+ case RADEON_SETPARAM_PCIGART_TABLE_SIZE:
+ dev_priv->gart_info.table_size = sp.value;
+ if (dev_priv->gart_info.table_size < RADEON_PCIGART_TABLE_SIZE)
+ dev_priv->gart_info.table_size = RADEON_PCIGART_TABLE_SIZE;
+ break;
default:
DRM_DEBUG("Invalid parameter %d\n", sp.param);
return DRM_ERR(EINVAL);
@@ -3168,9 +3160,7 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp)
{
if (dev->dev_private) {
drm_radeon_private_t *dev_priv = dev->dev_private;
- if (dev_priv->page_flipping) {
- radeon_do_cleanup_pageflip(dev);
- }
+ dev_priv->page_flipping = 0;
radeon_mem_release(filp, dev_priv->gart_heap);
radeon_mem_release(filp, dev_priv->fb_heap);
radeon_surfaces_release(filp, dev_priv);
@@ -3179,6 +3169,14 @@ void radeon_driver_preclose(drm_device_t * dev, DRMFILE filp)
void radeon_driver_lastclose(drm_device_t * dev)
{
+ if (dev->dev_private) {
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ if (dev_priv->sarea_priv &&
+ dev_priv->sarea_priv->pfCurrentPage != 0)
+ radeon_cp_dispatch_flip(dev);
+ }
+
radeon_do_release(dev);
}
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
index 3d5b3218b6f..690e0af8e7c 100644
--- a/drivers/char/drm/sis_drv.c
+++ b/drivers/char/drm/sis_drv.c
@@ -71,7 +71,7 @@ static struct drm_driver driver = {
.context_dtor = NULL,
.dma_quiescent = sis_idle,
.reclaim_buffers = NULL,
- .reclaim_buffers_locked = sis_reclaim_buffers_locked,
+ .reclaim_buffers_idlelocked = sis_reclaim_buffers_locked,
.lastclose = sis_lastclose,
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index c0539c6299c..13a9c5ca459 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -252,7 +252,7 @@ static int via_dma_init(DRM_IOCTL_ARGS)
break;
case VIA_DMA_INITIALIZED:
retcode = (dev_priv->ring.virtual_start != NULL) ?
- 0 : DRM_ERR(EFAULT);
+ 0 : DRM_ERR(EFAULT);
break;
default:
retcode = DRM_ERR(EINVAL);
@@ -432,56 +432,34 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
{
int paused, count;
volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
+ uint32_t reader,ptr;
+ paused = 0;
via_flush_write_combine();
- while (!*(via_get_dma(dev_priv) - 1)) ;
- *dev_priv->last_pause_ptr = pause_addr_lo;
+ (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1);
+ *paused_at = pause_addr_lo;
via_flush_write_combine();
-
- /*
- * The below statement is inserted to really force the flush.
- * Not sure it is needed.
- */
-
- while (!*dev_priv->last_pause_ptr) ;
+ (void) *paused_at;
+ reader = *(dev_priv->hw_addr_ptr);
+ ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
+ dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
- while (!*dev_priv->last_pause_ptr) ;
- paused = 0;
- count = 20;
-
- while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--) ;
- if ((count <= 8) && (count >= 0)) {
- uint32_t rgtr, ptr;
- rgtr = *(dev_priv->hw_addr_ptr);
- ptr = ((volatile char *)dev_priv->last_pause_ptr -
- dev_priv->dma_ptr) + dev_priv->dma_offset +
- (uint32_t) dev_priv->agpAddr + 4 - CMDBUF_ALIGNMENT_SIZE;
- if (rgtr <= ptr) {
- DRM_ERROR
- ("Command regulator\npaused at count %d, address %x, "
- "while current pause address is %x.\n"
- "Please mail this message to "
- "<unichrome-devel@lists.sourceforge.net>\n", count,
- rgtr, ptr);
- }
+ if ((ptr - reader) <= dev_priv->dma_diff ) {
+ count = 10000000;
+ while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
}
if (paused && !no_pci_fire) {
- uint32_t rgtr, ptr;
- uint32_t ptr_low;
+ reader = *(dev_priv->hw_addr_ptr);
+ if ((ptr - reader) == dev_priv->dma_diff) {
- count = 1000000;
- while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY)
- && count--) ;
+ /*
+ * There is a concern that these writes may stall the PCI bus
+ * if the GPU is not idle. However, idling the GPU first
+ * doesn't make a difference.
+ */
- rgtr = *(dev_priv->hw_addr_ptr);
- ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
- dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
-
- ptr_low = (ptr > 3 * CMDBUF_ALIGNMENT_SIZE) ?
- ptr - 3 * CMDBUF_ALIGNMENT_SIZE : 0;
- if (rgtr <= ptr && rgtr >= ptr_low) {
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
@@ -494,6 +472,9 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
static int via_wait_idle(drm_via_private_t * dev_priv)
{
int count = 10000000;
+
+ while (!(VIA_READ(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && count--);
+
while (count-- && (VIA_READ(VIA_REG_STATUS) &
(VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |
VIA_3D_ENG_BUSY))) ;
@@ -537,6 +518,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
uint32_t end_addr, end_addr_lo;
uint32_t command;
uint32_t agp_base;
+ uint32_t ptr;
+ uint32_t reader;
+ int count;
dev_priv->dma_low = 0;
@@ -554,7 +538,7 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
&pause_addr_hi, &pause_addr_lo, 1) - 1;
via_flush_write_combine();
- while (!*dev_priv->last_pause_ptr) ;
+ (void) *(volatile uint32_t *)dev_priv->last_pause_ptr;
VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
VIA_WRITE(VIA_REG_TRANSPACE, command);
@@ -566,6 +550,24 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
DRM_WRITEMEMORYBARRIER();
VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
VIA_READ(VIA_REG_TRANSPACE);
+
+ dev_priv->dma_diff = 0;
+
+ count = 10000000;
+ while (!(VIA_READ(0x41c) & 0x80000000) && count--);
+
+ reader = *(dev_priv->hw_addr_ptr);
+ ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) +
+ dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
+
+ /*
+ * This is the difference between where we tell the
+ * command reader to pause and where it actually pauses.
+ * This differs between hw implementation so we need to
+ * detect it.
+ */
+
+ dev_priv->dma_diff = ptr - reader;
}
static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
@@ -592,7 +594,6 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
uint32_t pause_addr_lo, pause_addr_hi;
uint32_t jump_addr_lo, jump_addr_hi;
volatile uint32_t *last_pause_ptr;
- uint32_t dma_low_save1, dma_low_save2;
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
@@ -619,31 +620,11 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
&pause_addr_lo, 0);
*last_pause_ptr = pause_addr_lo;
- dma_low_save1 = dev_priv->dma_low;
-
- /*
- * Now, set a trap that will pause the regulator if it tries to rerun the old
- * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
- * and reissues the jump command over PCI, while the regulator has already taken the jump
- * and actually paused at the current buffer end).
- * There appears to be no other way to detect this condition, since the hw_addr_pointer
- * does not seem to get updated immediately when a jump occurs.
- */
- last_pause_ptr =
- via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0) - 1;
- via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0);
- *last_pause_ptr = pause_addr_lo;
-
- dma_low_save2 = dev_priv->dma_low;
- dev_priv->dma_low = dma_low_save1;
- via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0);
- dev_priv->dma_low = dma_low_save2;
- via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
+ via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);
}
+
static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
{
via_cmdbuf_jump(dev_priv);
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
index bb9dde8b191..2d4957ab256 100644
--- a/drivers/char/drm/via_drv.c
+++ b/drivers/char/drm/via_drv.c
@@ -52,7 +52,8 @@ static struct drm_driver driver = {
.dma_quiescent = via_driver_dma_quiescent,
.dri_library_name = dri_library_name,
.reclaim_buffers = drm_core_reclaim_buffers,
- .reclaim_buffers_locked = via_reclaim_buffers_locked,
+ .reclaim_buffers_locked = NULL,
+ .reclaim_buffers_idlelocked = via_reclaim_buffers_locked,
.lastclose = via_lastclose,
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index 8b8778d4a42..b46ca8e6306 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -29,11 +29,11 @@
#define DRIVER_NAME "via"
#define DRIVER_DESC "VIA Unichrome / Pro"
-#define DRIVER_DATE "20061227"
+#define DRIVER_DATE "20070202"
#define DRIVER_MAJOR 2
#define DRIVER_MINOR 11
-#define DRIVER_PATCHLEVEL 0
+#define DRIVER_PATCHLEVEL 1
#include "via_verifier.h"
@@ -93,6 +93,7 @@ typedef struct drm_via_private {
unsigned long vram_offset;
unsigned long agp_offset;
drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
+ uint32_t dma_diff;
} drm_via_private_t;
enum via_family {
diff --git a/drivers/char/drm/via_mm.h b/drivers/char/drm/via_mm.h
deleted file mode 100644
index d57efda57c7..00000000000
--- a/drivers/char/drm/via_mm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-#ifndef _via_drm_mm_h_
-#define _via_drm_mm_h_
-
-typedef struct {
- unsigned int context;
- unsigned int size;
- unsigned long offset;
- unsigned long free;
-} drm_via_mm_t;
-
-typedef struct {
- unsigned int size;
- unsigned long handle;
- void *virtual;
-} drm_via_dma_t;
-
-#endif
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c
index 3d7efc26aad..334ad5bbe6b 100644
--- a/drivers/char/ds1620.c
+++ b/drivers/char/ds1620.c
@@ -4,7 +4,6 @@
*/
#include <linux/module.h>
#include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/capability.h>
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index db984e481d4..9b8278e1f4f 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -32,7 +32,6 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#include <asm/atarihw.h>
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index d8dbdb91623..abde6ddefe6 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -62,7 +62,6 @@
#include <linux/init.h> /* for __init, module_{init,exit} */
#include <linux/poll.h> /* for POLLIN, etc. */
#include <linux/dtlk.h> /* local header file for DoubleTalk values */
-#include <linux/smp_lock.h>
#ifdef TRACING
#define TRACE_TEXT(str) printk(str);
@@ -325,16 +324,22 @@ static int dtlk_release(struct inode *inode, struct file *file)
static int __init dtlk_init(void)
{
+ int err;
+
dtlk_port_lpc = 0;
dtlk_port_tts = 0;
dtlk_busy = 0;
dtlk_major = register_chrdev(0, "dtlk", &dtlk_fops);
- if (dtlk_major == 0) {
+ if (dtlk_major < 0) {
printk(KERN_ERR "DoubleTalk PC - cannot register device\n");
- return 0;
+ return dtlk_major;
+ }
+ err = dtlk_dev_probe();
+ if (err) {
+ unregister_chrdev(dtlk_major, "dtlk");
+ return err;
}
- if (dtlk_dev_probe() == 0)
- printk(", MAJOR %d\n", dtlk_major);
+ printk(", MAJOR %d\n", dtlk_major);
init_waitqueue_head(&dtlk_process_list);
diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c
index 77f58ed6d59..020011495d9 100644
--- a/drivers/char/ec3104_keyb.c
+++ b/drivers/char/ec3104_keyb.c
@@ -41,7 +41,6 @@
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/kbd_kern.h>
-#include <linux/smp_lock.h>
#include <linux/bitops.h>
#include <asm/keyboard.h>
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index de5be30484a..c6c56fb8ba5 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -949,7 +949,7 @@ static int block_til_ready(struct tty_struct *tty,
} /* End forever while */
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&ch->open_wait, &wait);
if (!tty_hung_up_p(filp))
ch->count++;
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index 23b25ada65e..9e1fc02967f 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -12,7 +12,7 @@
*
* This driver allows use of the real time clock (built into
* nearly all computers) from user space. It exports the /dev/rtc
- * interface supporting various ioctl() and also the /proc/dev/rtc
+ * interface supporting various ioctl() and also the /proc/driver/rtc
* pseudo-file for status information.
*
* The ioctls can be used to set the interrupt behaviour where
@@ -207,7 +207,7 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf,
sizeof(unsigned long);
}
out:
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&gen_rtc_wait, &wait);
return retval;
@@ -377,7 +377,7 @@ static int gen_rtc_release(struct inode *inode, struct file *file)
#ifdef CONFIG_PROC_FS
/*
- * Info exported via "/proc/rtc".
+ * Info exported via "/proc/driver/rtc".
*/
static int gen_rtc_proc_output(char *buf)
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
index ae76a9ffe89..f0e7263dfcd 100644
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -44,7 +44,6 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/reboot.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 0f9ed7b46a6..322bc5f7d86 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -111,7 +111,7 @@ static int last_hvc = -1;
* lock held. If successful, this function increments the kobject reference
* count against the target hvc_struct so it should be released when finished.
*/
-struct hvc_struct *hvc_get_by_index(int index)
+static struct hvc_struct *hvc_get_by_index(int index)
{
struct hvc_struct *hp;
unsigned long flags;
@@ -150,7 +150,8 @@ static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
* hvc_console_setup() finds adapters.
*/
-void hvc_console_print(struct console *co, const char *b, unsigned count)
+static void hvc_console_print(struct console *co, const char *b,
+ unsigned count)
{
char c[N_OUTBUF] __ALIGNED__;
unsigned i = 0, n = 0;
@@ -208,7 +209,7 @@ static int __init hvc_console_setup(struct console *co, char *options)
return 0;
}
-struct console hvc_con_driver = {
+static struct console hvc_con_driver = {
.name = "hvc",
.write = hvc_console_print,
.device = hvc_console_device,
@@ -278,7 +279,6 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
return 0;
}
-EXPORT_SYMBOL(hvc_instantiate);
/* Wake the sleeping khvcd */
static void hvc_kick(void)
@@ -792,7 +792,6 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
return hp;
}
-EXPORT_SYMBOL(hvc_alloc);
int __devexit hvc_remove(struct hvc_struct *hp)
{
@@ -828,11 +827,10 @@ int __devexit hvc_remove(struct hvc_struct *hp)
tty_hangup(tty);
return 0;
}
-EXPORT_SYMBOL(hvc_remove);
/* Driver initialization. Follow console initialization. This is where the TTY
* interfaces start to become available. */
-int __init hvc_init(void)
+static int __init hvc_init(void)
{
struct tty_driver *drv;
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index ec420fe8a90..b37f1d5a5be 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -579,7 +579,7 @@ static int hvc_find_vtys(void)
if (!vtermno)
continue;
- if (!device_is_compatible(vty, "IBM,iSeries-vty"))
+ if (!of_device_is_compatible(vty, "IBM,iSeries-vty"))
continue;
if (num_found == 0)
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index 94a542e20ef..79711aa4b41 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -157,7 +157,7 @@ static int hvc_find_vtys(void)
if (!vtermno)
continue;
- if (device_is_compatible(vty, "hvterm1")) {
+ if (of_device_is_compatible(vty, "hvterm1")) {
hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
++num_found;
}
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index 5f3acd8e64b..7cda04b3353 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -91,3 +91,17 @@ config HW_RANDOM_OMAP
module will be called omap-rng.
If unsure, say Y.
+
+config HW_RANDOM_PASEMI
+ tristate "PA Semi HW Random Number Generator support"
+ depends on HW_RANDOM && PPC_PASEMI
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on PA6T-1682M processor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pasemi-rng.
+
+ If unsure, say Y.
+
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index c41fa19454e..c8b7300e2fb 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
+obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index cc1046e6ee0..4ae9811d1a6 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -24,10 +24,11 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/module.h>
+#include <linux/hw_random.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/hw_random.h>
+#include <linux/stop_machine.h>
#include <asm/io.h>
@@ -217,30 +218,117 @@ static struct hwrng intel_rng = {
.data_read = intel_rng_data_read,
};
+struct intel_rng_hw {
+ struct pci_dev *dev;
+ void __iomem *mem;
+ u8 bios_cntl_off;
+ u8 bios_cntl_val;
+ u8 fwh_dec_en1_off;
+ u8 fwh_dec_en1_val;
+};
-#ifdef CONFIG_SMP
-static char __initdata waitflag;
+static int __init intel_rng_hw_init(void *_intel_rng_hw)
+{
+ struct intel_rng_hw *intel_rng_hw = _intel_rng_hw;
+ u8 mfc, dvc;
+
+ /* interrupts disabled in stop_machine_run call */
+
+ if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))
+ pci_write_config_byte(intel_rng_hw->dev,
+ intel_rng_hw->fwh_dec_en1_off,
+ intel_rng_hw->fwh_dec_en1_val |
+ FWH_F8_EN_MASK);
+ if (!(intel_rng_hw->bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))
+ pci_write_config_byte(intel_rng_hw->dev,
+ intel_rng_hw->bios_cntl_off,
+ intel_rng_hw->bios_cntl_val |
+ BIOS_CNTL_WRITE_ENABLE_MASK);
+
+ writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);
+ writeb(INTEL_FWH_READ_ID_CMD, intel_rng_hw->mem);
+ mfc = readb(intel_rng_hw->mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
+ dvc = readb(intel_rng_hw->mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
+ writeb(INTEL_FWH_RESET_CMD, intel_rng_hw->mem);
+
+ if (!(intel_rng_hw->bios_cntl_val &
+ (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
+ pci_write_config_byte(intel_rng_hw->dev,
+ intel_rng_hw->bios_cntl_off,
+ intel_rng_hw->bios_cntl_val);
+ if (!(intel_rng_hw->fwh_dec_en1_val & FWH_F8_EN_MASK))
+ pci_write_config_byte(intel_rng_hw->dev,
+ intel_rng_hw->fwh_dec_en1_off,
+ intel_rng_hw->fwh_dec_en1_val);
-static void __init intel_init_wait(void *unused)
+ if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
+ (dvc != INTEL_FWH_DEVICE_CODE_8M &&
+ dvc != INTEL_FWH_DEVICE_CODE_4M)) {
+ printk(KERN_ERR PFX "FWH not detected\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,
+ struct pci_dev *dev)
{
- while (waitflag)
- cpu_relax();
+ intel_rng_hw->bios_cntl_val = 0xff;
+ intel_rng_hw->fwh_dec_en1_val = 0xff;
+ intel_rng_hw->dev = dev;
+
+ /* Check for Intel 82802 */
+ if (dev->device < 0x2640) {
+ intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
+ intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_OLD;
+ } else {
+ intel_rng_hw->fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
+ intel_rng_hw->bios_cntl_off = BIOS_CNTL_REG_NEW;
+ }
+
+ pci_read_config_byte(dev, intel_rng_hw->fwh_dec_en1_off,
+ &intel_rng_hw->fwh_dec_en1_val);
+ pci_read_config_byte(dev, intel_rng_hw->bios_cntl_off,
+ &intel_rng_hw->bios_cntl_val);
+
+ if ((intel_rng_hw->bios_cntl_val &
+ (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. "
+ KERN_WARNING PFX "If you can't or\n don't want to "
+ KERN_WARNING PFX "disable this in firmware setup, and "
+ KERN_WARNING PFX "if\n you are certain that your "
+ KERN_WARNING PFX "system has a functional\n RNG, try"
+ KERN_WARNING PFX "using the 'no_fwh_detect' option.\n";
+
+ if (no_fwh_detect)
+ return -ENODEV;
+ printk(warning);
+ return -EBUSY;
+ }
+
+ intel_rng_hw->mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
+ if (intel_rng_hw->mem == NULL)
+ return -EBUSY;
+
+ return 0;
}
-#endif
+
static int __init mod_init(void)
{
int err = -ENODEV;
- unsigned i;
+ int i;
struct pci_dev *dev = NULL;
- void __iomem *mem;
- unsigned long flags;
- u8 bios_cntl_off, fwh_dec_en1_off;
- u8 bios_cntl_val = 0xff, fwh_dec_en1_val = 0xff;
- u8 hw_status, mfc, dvc;
+ void __iomem *mem = mem;
+ u8 hw_status;
+ struct intel_rng_hw *intel_rng_hw;
for (i = 0; !dev && pci_tbl[i].vendor; ++i)
- dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL);
+ dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device,
+ NULL);
if (!dev)
goto out; /* Device not found. */
@@ -250,39 +338,18 @@ static int __init mod_init(void)
goto fwh_done;
}
- /* Check for Intel 82802 */
- if (dev->device < 0x2640) {
- fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
- bios_cntl_off = BIOS_CNTL_REG_OLD;
- } else {
- fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
- bios_cntl_off = BIOS_CNTL_REG_NEW;
- }
-
- pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val);
- pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
-
- if ((bios_cntl_val &
- (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";
-
+ intel_rng_hw = kmalloc(sizeof(*intel_rng_hw), GFP_KERNEL);
+ if (!intel_rng_hw) {
pci_dev_put(dev);
- if (no_fwh_detect)
- goto fwh_done;
- printk(warning);
- err = -EBUSY;
goto out;
}
- mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
- if (mem == NULL) {
+ err = intel_init_hw_struct(intel_rng_hw, dev);
+ if (err) {
pci_dev_put(dev);
- err = -EBUSY;
+ kfree(intel_rng_hw);
+ if (err == -ENODEV)
+ goto fwh_done;
goto out;
}
@@ -290,59 +357,18 @@ static int __init mod_init(void)
* Since the BIOS code/data is going to disappear from its normal
* location with the Read ID command, all activity on the system
* must be stopped until the state is back to normal.
+ *
+ * Use stop_machine_run because IPIs can be blocked by disabling
+ * interrupts.
*/
-#ifdef CONFIG_SMP
- set_mb(waitflag, 1);
- if (smp_call_function(intel_init_wait, NULL, 1, 0) != 0) {
- set_mb(waitflag, 0);
- pci_dev_put(dev);
- printk(KERN_ERR PFX "cannot run on all processors\n");
- err = -EAGAIN;
- goto err_unmap;
- }
-#endif
- local_irq_save(flags);
-
- if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
- pci_write_config_byte(dev,
- fwh_dec_en1_off,
- fwh_dec_en1_val | FWH_F8_EN_MASK);
- if (!(bios_cntl_val & BIOS_CNTL_WRITE_ENABLE_MASK))
- pci_write_config_byte(dev,
- bios_cntl_off,
- bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK);
-
- writeb(INTEL_FWH_RESET_CMD, mem);
- writeb(INTEL_FWH_READ_ID_CMD, mem);
- mfc = readb(mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
- dvc = readb(mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
- writeb(INTEL_FWH_RESET_CMD, mem);
-
- if (!(bios_cntl_val &
- (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
- pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val);
- if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
- pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val);
-
- local_irq_restore(flags);
-#ifdef CONFIG_SMP
- /* Tell other CPUs to resume. */
- set_mb(waitflag, 0);
-#endif
-
- iounmap(mem);
+ err = stop_machine_run(intel_rng_hw_init, intel_rng_hw, NR_CPUS);
pci_dev_put(dev);
-
- if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
- (dvc != INTEL_FWH_DEVICE_CODE_8M &&
- dvc != INTEL_FWH_DEVICE_CODE_4M)) {
- printk(KERN_ERR PFX "FWH not detected\n");
- err = -ENODEV;
+ iounmap(intel_rng_hw->mem);
+ kfree(intel_rng_hw);
+ if (err)
goto out;
- }
fwh_done:
-
err = -ENOMEM;
mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
if (!mem)
@@ -352,22 +378,21 @@ fwh_done:
/* Check for Random Number Generator */
err = -ENODEV;
hw_status = hwstatus_get(mem);
- if ((hw_status & INTEL_RNG_PRESENT) == 0)
- goto err_unmap;
+ if ((hw_status & INTEL_RNG_PRESENT) == 0) {
+ iounmap(mem);
+ goto out;
+ }
printk(KERN_INFO "Intel 82802 RNG detected\n");
err = hwrng_register(&intel_rng);
if (err) {
printk(KERN_ERR PFX "RNG registering failed (%d)\n",
err);
- goto err_unmap;
+ iounmap(mem);
}
out:
return err;
-err_unmap:
- iounmap(mem);
- goto out;
}
static void __exit mod_exit(void)
diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
new file mode 100644
index 00000000000..fa6040b6c8f
--- /dev/null
+++ b/drivers/char/hw_random/pasemi-rng.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Maintained by: Olof Johansson <olof@lixom.net>
+ *
+ * Driver for the PWRficient onchip rng
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+#include <asm/of_platform.h>
+#include <asm/io.h>
+
+#define SDCRNG_CTL_REG 0x00
+#define SDCRNG_CTL_FVLD_M 0x0000f000
+#define SDCRNG_CTL_FVLD_S 12
+#define SDCRNG_CTL_KSZ 0x00000800
+#define SDCRNG_CTL_RSRC_CRG 0x00000010
+#define SDCRNG_CTL_RSRC_RRG 0x00000000
+#define SDCRNG_CTL_CE 0x00000004
+#define SDCRNG_CTL_RE 0x00000002
+#define SDCRNG_CTL_DR 0x00000001
+#define SDCRNG_CTL_SELECT_RRG_RNG (SDCRNG_CTL_RE | SDCRNG_CTL_RSRC_RRG)
+#define SDCRNG_CTL_SELECT_CRG_RNG (SDCRNG_CTL_CE | SDCRNG_CTL_RSRC_CRG)
+#define SDCRNG_VAL_REG 0x20
+
+#define MODULE_NAME "pasemi_rng"
+
+static int pasemi_rng_data_present(struct hwrng *rng)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+
+ return (in_le32(rng_regs + SDCRNG_CTL_REG)
+ & SDCRNG_CTL_FVLD_M) ? 1 : 0;
+}
+
+static int pasemi_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+ *data = in_le32(rng_regs + SDCRNG_VAL_REG);
+ return 4;
+}
+
+static int pasemi_rng_init(struct hwrng *rng)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+ u32 ctl;
+
+ ctl = SDCRNG_CTL_DR | SDCRNG_CTL_SELECT_RRG_RNG | SDCRNG_CTL_KSZ;
+ out_le32(rng_regs + SDCRNG_CTL_REG, ctl);
+ out_le32(rng_regs + SDCRNG_CTL_REG, ctl & ~SDCRNG_CTL_DR);
+
+ return 0;
+}
+
+static void pasemi_rng_cleanup(struct hwrng *rng)
+{
+ void __iomem *rng_regs = (void __iomem *)rng->priv;
+ u32 ctl;
+
+ ctl = SDCRNG_CTL_RE | SDCRNG_CTL_CE;
+ out_le32(rng_regs + SDCRNG_CTL_REG,
+ in_le32(rng_regs + SDCRNG_CTL_REG) & ~ctl);
+}
+
+static struct hwrng pasemi_rng = {
+ .name = MODULE_NAME,
+ .init = pasemi_rng_init,
+ .cleanup = pasemi_rng_cleanup,
+ .data_present = pasemi_rng_data_present,
+ .data_read = pasemi_rng_data_read,
+};
+
+static int __devinit rng_probe(struct of_device *ofdev,
+ const struct of_device_id *match)
+{
+ void __iomem *rng_regs;
+ struct device_node *rng_np = ofdev->node;
+ struct resource res;
+ int err = 0;
+
+ err = of_address_to_resource(rng_np, 0, &res);
+ if (err)
+ return -ENODEV;
+
+ rng_regs = ioremap(res.start, 0x100);
+
+ if (!rng_regs)
+ return -ENOMEM;
+
+ pasemi_rng.priv = (unsigned long)rng_regs;
+
+ printk(KERN_INFO "Registering PA Semi RNG\n");
+
+ err = hwrng_register(&pasemi_rng);
+
+ if (err)
+ iounmap(rng_regs);
+
+ return err;
+}
+
+static int __devexit rng_remove(struct of_device *dev)
+{
+ void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv;
+
+ hwrng_unregister(&pasemi_rng);
+ iounmap(rng_regs);
+
+ return 0;
+}
+
+static struct of_device_id rng_match[] = {
+ {
+ .compatible = "1682m-rng",
+ },
+ {},
+};
+
+static struct of_platform_driver rng_driver = {
+ .name = "pasemi-rng",
+ .match_table = rng_match,
+ .probe = rng_probe,
+ .remove = rng_remove,
+};
+
+static int __init rng_init(void)
+{
+ return of_register_platform_driver(&rng_driver);
+}
+module_init(rng_init);
+
+static void __exit rng_exit(void)
+{
+ of_unregister_platform_driver(&rng_driver);
+}
+module_exit(rng_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
+MODULE_DESCRIPTION("H/W RNG driver for PA Semi processor");
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 9ebf84d1865..ec435cb25c4 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -26,7 +26,6 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/pci.h>
#include <linux/hw_random.h>
#include <asm/io.h>
#include <asm/msr.h>
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 353d9f3cf8d..0289705967d 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -22,6 +22,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/dmi.h>
+#include <linux/capability.h>
#include <asm/uaccess.h>
#include <asm/io.h>
diff --git a/drivers/char/ip27-rtc.c b/drivers/char/ip27-rtc.c
index a48da02aad2..932264a657d 100644
--- a/drivers/char/ip27-rtc.c
+++ b/drivers/char/ip27-rtc.c
@@ -35,7 +35,6 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
-#include <linux/smp_lock.h>
#include <asm/m48t35.h>
#include <asm/sn/ioc3.h>
diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig
index a6dcb291815..b894f67fdf1 100644
--- a/drivers/char/ipmi/Kconfig
+++ b/drivers/char/ipmi/Kconfig
@@ -3,6 +3,8 @@
#
menu "IPMI"
+ depends on HAS_IOMEM
+
config IPMI_HANDLER
tristate 'IPMI top-level message handler'
help
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index e22146546ad..6c5d15de331 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -9,6 +9,7 @@
* source@mvista.com
*
* Copyright 2002 MontaVista Software Inc.
+ * Copyright 2006 IBM Corp., Christian Krafft <krafft@de.ibm.com>
*
* 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
@@ -64,6 +65,11 @@
#include <linux/string.h>
#include <linux/ctype.h>
+#ifdef CONFIG_PPC_OF
+#include <asm/of_device.h>
+#include <asm/of_platform.h>
+#endif
+
#define PFX "ipmi_si: "
/* Measure times between events in the driver. */
@@ -76,6 +82,12 @@
#define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a
short timeout */
+/* Bit for BMC global enables. */
+#define IPMI_BMC_RCV_MSG_INTR 0x01
+#define IPMI_BMC_EVT_MSG_INTR 0x02
+#define IPMI_BMC_EVT_MSG_BUFF 0x04
+#define IPMI_BMC_SYS_LOG 0x08
+
enum si_intf_state {
SI_NORMAL,
SI_GETTING_FLAGS,
@@ -84,7 +96,9 @@ enum si_intf_state {
SI_CLEARING_FLAGS_THEN_SET_IRQ,
SI_GETTING_MESSAGES,
SI_ENABLE_INTERRUPTS1,
- SI_ENABLE_INTERRUPTS2
+ SI_ENABLE_INTERRUPTS2,
+ SI_DISABLE_INTERRUPTS1,
+ SI_DISABLE_INTERRUPTS2
/* FIXME - add watchdog stuff. */
};
@@ -333,6 +347,17 @@ static void start_enable_irq(struct smi_info *smi_info)
smi_info->si_state = SI_ENABLE_INTERRUPTS1;
}
+static void start_disable_irq(struct smi_info *smi_info)
+{
+ unsigned char msg[2];
+
+ msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+ msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+
+ smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+ smi_info->si_state = SI_DISABLE_INTERRUPTS1;
+}
+
static void start_clear_flags(struct smi_info *smi_info)
{
unsigned char msg[3];
@@ -353,7 +378,7 @@ static void start_clear_flags(struct smi_info *smi_info)
static inline void disable_si_irq(struct smi_info *smi_info)
{
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
- disable_irq_nosync(smi_info->irq);
+ start_disable_irq(smi_info);
smi_info->interrupt_disabled = 1;
}
}
@@ -361,7 +386,7 @@ static inline void disable_si_irq(struct smi_info *smi_info)
static inline void enable_si_irq(struct smi_info *smi_info)
{
if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
- enable_irq(smi_info->irq);
+ start_enable_irq(smi_info);
smi_info->interrupt_disabled = 0;
}
}
@@ -583,7 +608,9 @@ static void handle_transaction_done(struct smi_info *smi_info)
} else {
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
- msg[2] = msg[3] | 1; /* enable msg queue int */
+ msg[2] = (msg[3] |
+ IPMI_BMC_RCV_MSG_INTR |
+ IPMI_BMC_EVT_MSG_INTR);
smi_info->handlers->start_transaction(
smi_info->si_sm, msg, 3);
smi_info->si_state = SI_ENABLE_INTERRUPTS2;
@@ -605,6 +632,45 @@ static void handle_transaction_done(struct smi_info *smi_info)
smi_info->si_state = SI_NORMAL;
break;
}
+
+ case SI_DISABLE_INTERRUPTS1:
+ {
+ unsigned char msg[4];
+
+ /* We got the flags from the SMI, now handle them. */
+ smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+ if (msg[2] != 0) {
+ printk(KERN_WARNING
+ "ipmi_si: Could not disable interrupts"
+ ", failed get.\n");
+ smi_info->si_state = SI_NORMAL;
+ } else {
+ msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+ msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+ msg[2] = (msg[3] &
+ ~(IPMI_BMC_RCV_MSG_INTR |
+ IPMI_BMC_EVT_MSG_INTR));
+ smi_info->handlers->start_transaction(
+ smi_info->si_sm, msg, 3);
+ smi_info->si_state = SI_DISABLE_INTERRUPTS2;
+ }
+ break;
+ }
+
+ case SI_DISABLE_INTERRUPTS2:
+ {
+ unsigned char msg[4];
+
+ /* We got the flags from the SMI, now handle them. */
+ smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
+ if (msg[2] != 0) {
+ printk(KERN_WARNING
+ "ipmi_si: Could not disable interrupts"
+ ", failed set.\n");
+ }
+ smi_info->si_state = SI_NORMAL;
+ break;
+ }
}
}
@@ -858,9 +924,6 @@ static void smi_timeout(unsigned long data)
struct timeval t;
#endif
- if (atomic_read(&smi_info->stop_operation))
- return;
-
spin_lock_irqsave(&(smi_info->si_lock), flags);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
@@ -916,15 +979,11 @@ static irqreturn_t si_irq_handler(int irq, void *data)
smi_info->interrupts++;
spin_unlock(&smi_info->count_lock);
- if (atomic_read(&smi_info->stop_operation))
- goto out;
-
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
smi_event_handler(smi_info, 0);
- out:
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
return IRQ_HANDLED;
}
@@ -1006,6 +1065,7 @@ static DEFINE_MUTEX(smi_infos_lock);
static int smi_num; /* Used to sequence the SMIs */
#define DEFAULT_REGSPACING 1
+#define DEFAULT_REGSIZE 1
static int si_trydefaults = 1;
static char *si_type[SI_MAX_PARMS];
@@ -1111,7 +1171,7 @@ static int std_irq_setup(struct smi_info *info)
if (info->si_type == SI_BT) {
rv = request_irq(info->irq,
si_bt_irq_handler,
- IRQF_DISABLED,
+ IRQF_SHARED | IRQF_DISABLED,
DEVICE_NAME,
info);
if (!rv)
@@ -1121,7 +1181,7 @@ static int std_irq_setup(struct smi_info *info)
} else
rv = request_irq(info->irq,
si_irq_handler,
- IRQF_DISABLED,
+ IRQF_SHARED | IRQF_DISABLED,
DEVICE_NAME,
info);
if (rv) {
@@ -1701,15 +1761,11 @@ static u32 ipmi_acpi_gpe(void *context)
smi_info->interrupts++;
spin_unlock(&smi_info->count_lock);
- if (atomic_read(&smi_info->stop_operation))
- goto out;
-
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
smi_event_handler(smi_info, 0);
- out:
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
return ACPI_INTERRUPT_HANDLED;
@@ -2133,12 +2189,15 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
info->irq_setup = std_irq_setup;
info->dev = &pdev->dev;
+ pci_set_drvdata(pdev, info);
return try_smi_init(info);
}
static void __devexit ipmi_pci_remove(struct pci_dev *pdev)
{
+ struct smi_info *info = pci_get_drvdata(pdev);
+ cleanup_one_si(info);
}
#ifdef CONFIG_PM
@@ -2172,6 +2231,99 @@ static struct pci_driver ipmi_pci_driver = {
#endif /* CONFIG_PCI */
+#ifdef CONFIG_PPC_OF
+static int __devinit ipmi_of_probe(struct of_device *dev,
+ const struct of_device_id *match)
+{
+ struct smi_info *info;
+ struct resource resource;
+ const int *regsize, *regspacing, *regshift;
+ struct device_node *np = dev->node;
+ int ret;
+ int proplen;
+
+ dev_info(&dev->dev, PFX "probing via device tree\n");
+
+ ret = of_address_to_resource(np, 0, &resource);
+ if (ret) {
+ dev_warn(&dev->dev, PFX "invalid address from OF\n");
+ return ret;
+ }
+
+ regsize = get_property(np, "reg-size", &proplen);
+ if (regsize && proplen != 4) {
+ dev_warn(&dev->dev, PFX "invalid regsize from OF\n");
+ return -EINVAL;
+ }
+
+ regspacing = get_property(np, "reg-spacing", &proplen);
+ if (regspacing && proplen != 4) {
+ dev_warn(&dev->dev, PFX "invalid regspacing from OF\n");
+ return -EINVAL;
+ }
+
+ regshift = get_property(np, "reg-shift", &proplen);
+ if (regshift && proplen != 4) {
+ dev_warn(&dev->dev, PFX "invalid regshift from OF\n");
+ return -EINVAL;
+ }
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+
+ if (!info) {
+ dev_err(&dev->dev,
+ PFX "could not allocate memory for OF probe\n");
+ return -ENOMEM;
+ }
+
+ info->si_type = (enum si_type) match->data;
+ info->addr_source = "device-tree";
+ info->io_setup = mem_setup;
+ info->irq_setup = std_irq_setup;
+
+ info->io.addr_type = IPMI_MEM_ADDR_SPACE;
+ info->io.addr_data = resource.start;
+
+ info->io.regsize = regsize ? *regsize : DEFAULT_REGSIZE;
+ info->io.regspacing = regspacing ? *regspacing : DEFAULT_REGSPACING;
+ info->io.regshift = regshift ? *regshift : 0;
+
+ info->irq = irq_of_parse_and_map(dev->node, 0);
+ info->dev = &dev->dev;
+
+ dev_dbg(&dev->dev, "addr 0x%lx regsize %ld spacing %ld irq %x\n",
+ info->io.addr_data, info->io.regsize, info->io.regspacing,
+ info->irq);
+
+ dev->dev.driver_data = (void*) info;
+
+ return try_smi_init(info);
+}
+
+static int __devexit ipmi_of_remove(struct of_device *dev)
+{
+ cleanup_one_si(dev->dev.driver_data);
+ return 0;
+}
+
+static struct of_device_id ipmi_match[] =
+{
+ { .type = "ipmi", .compatible = "ipmi-kcs", .data = (void *)(unsigned long) SI_KCS },
+ { .type = "ipmi", .compatible = "ipmi-smic", .data = (void *)(unsigned long) SI_SMIC },
+ { .type = "ipmi", .compatible = "ipmi-bt", .data = (void *)(unsigned long) SI_BT },
+ {},
+};
+
+static struct of_platform_driver ipmi_of_platform_driver =
+{
+ .name = "ipmi",
+ .match_table = ipmi_match,
+ .probe = ipmi_of_probe,
+ .remove = __devexit_p(ipmi_of_remove),
+};
+#endif /* CONFIG_PPC_OF */
+
+
static int try_get_dev_id(struct smi_info *smi_info)
{
unsigned char msg[2];
@@ -2801,6 +2953,10 @@ static __devinit int init_ipmi_si(void)
}
#endif
+#ifdef CONFIG_PPC_OF
+ of_register_platform_driver(&ipmi_of_platform_driver);
+#endif
+
if (si_trydefaults) {
mutex_lock(&smi_infos_lock);
if (list_empty(&smi_infos)) {
@@ -2838,28 +2994,33 @@ static void cleanup_one_si(struct smi_info *to_clean)
list_del(&to_clean->link);
- /* Tell the timer and interrupt handlers that we are shutting
- down. */
- spin_lock_irqsave(&(to_clean->si_lock), flags);
- spin_lock(&(to_clean->msg_lock));
-
+ /* Tell the driver that we are shutting down. */
atomic_inc(&to_clean->stop_operation);
- if (to_clean->irq_cleanup)
- to_clean->irq_cleanup(to_clean);
-
- spin_unlock(&(to_clean->msg_lock));
- spin_unlock_irqrestore(&(to_clean->si_lock), flags);
-
- /* Wait until we know that we are out of any interrupt
- handlers might have been running before we freed the
- interrupt. */
- synchronize_sched();
-
+ /* Make sure the timer and thread are stopped and will not run
+ again. */
wait_for_timer_and_thread(to_clean);
- /* Interrupts and timeouts are stopped, now make sure the
- interface is in a clean state. */
+ /* Timeouts are stopped, now make sure the interrupts are off
+ for the device. A little tricky with locks to make sure
+ there are no races. */
+ spin_lock_irqsave(&to_clean->si_lock, flags);
+ while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
+ spin_unlock_irqrestore(&to_clean->si_lock, flags);
+ poll(to_clean);
+ schedule_timeout_uninterruptible(1);
+ spin_lock_irqsave(&to_clean->si_lock, flags);
+ }
+ disable_si_irq(to_clean);
+ spin_unlock_irqrestore(&to_clean->si_lock, flags);
+ while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
+ poll(to_clean);
+ schedule_timeout_uninterruptible(1);
+ }
+
+ /* Clean up interrupts and make sure that everything is done. */
+ if (to_clean->irq_cleanup)
+ to_clean->irq_cleanup(to_clean);
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
poll(to_clean);
schedule_timeout_uninterruptible(1);
@@ -2898,6 +3059,10 @@ static __exit void cleanup_ipmi_si(void)
pci_unregister_driver(&ipmi_pci_driver);
#endif
+#ifdef CONFIG_PPC_OF
+ of_unregister_platform_driver(&ipmi_of_platform_driver);
+#endif
+
mutex_lock(&smi_infos_lock);
list_for_each_entry_safe(e, tmp_e, &smi_infos, link)
cleanup_one_si(e);
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 6b634e8d951..147c12047cf 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -39,6 +39,7 @@
#include <linux/miscdevice.h>
#include <linux/init.h>
#include <linux/completion.h>
+#include <linux/kdebug.h>
#include <linux/rwsem.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
@@ -49,9 +50,18 @@
#include <linux/poll.h>
#include <linux/string.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
#include <asm/atomic.h>
-#ifdef CONFIG_X86_LOCAL_APIC
-#include <asm/apic.h>
+
+#ifdef CONFIG_X86
+/* This is ugly, but I've determined that x86 is the only architecture
+ that can reasonably support the IPMI NMI watchdog timeout at this
+ time. If another architecture adds this capability somehow, it
+ will have to be a somewhat different mechanism and I have no idea
+ how it will work. So in the unlikely event that another
+ architecture supports this, we can figure out a good generic
+ mechanism for it at that time. */
+#define HAVE_DIE_NMI_POST
#endif
#define PFX "IPMI Watchdog: "
@@ -317,6 +327,11 @@ static unsigned char ipmi_version_minor;
/* If a pretimeout occurs, this is used to allow only one panic to happen. */
static atomic_t preop_panic_excl = ATOMIC_INIT(-1);
+#ifdef HAVE_DIE_NMI_POST
+static int testing_nmi;
+static int nmi_handler_registered;
+#endif
+
static int ipmi_heartbeat(void);
static void panic_halt_ipmi_heartbeat(void);
@@ -358,6 +373,10 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
int hbnow = 0;
+ /* These can be cleared as we are setting the timeout. */
+ ipmi_start_timer_on_heartbeat = 0;
+ pretimeout_since_last_heartbeat = 0;
+
data[0] = 0;
WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
@@ -432,13 +451,12 @@ static int ipmi_set_timeout(int do_heartbeat)
wait_for_completion(&set_timeout_wait);
+ mutex_unlock(&set_timeout_lock);
+
if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
|| ((send_heartbeat_now)
&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
- {
rv = ipmi_heartbeat();
- }
- mutex_unlock(&set_timeout_lock);
out:
return rv;
@@ -518,12 +536,10 @@ static int ipmi_heartbeat(void)
int rv;
struct ipmi_system_interface_addr addr;
- if (ipmi_ignore_heartbeat) {
+ if (ipmi_ignore_heartbeat)
return 0;
- }
if (ipmi_start_timer_on_heartbeat) {
- ipmi_start_timer_on_heartbeat = 0;
ipmi_watchdog_state = action_val;
return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
} else if (pretimeout_since_last_heartbeat) {
@@ -531,7 +547,6 @@ static int ipmi_heartbeat(void)
We don't want to set the action, though, we want to
leave that alone (thus it can't be combined with the
above operation. */
- pretimeout_since_last_heartbeat = 0;
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
}
@@ -919,6 +934,45 @@ static void ipmi_register_watchdog(int ipmi_intf)
printk(KERN_CRIT PFX "Unable to register misc device\n");
}
+#ifdef HAVE_DIE_NMI_POST
+ if (nmi_handler_registered) {
+ int old_pretimeout = pretimeout;
+ int old_timeout = timeout;
+ int old_preop_val = preop_val;
+
+ /* Set the pretimeout to go off in a second and give
+ ourselves plenty of time to stop the timer. */
+ ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+ preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */
+ pretimeout = 99;
+ timeout = 100;
+
+ testing_nmi = 1;
+
+ rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
+ if (rv) {
+ printk(KERN_WARNING PFX "Error starting timer to"
+ " test NMI: 0x%x. The NMI pretimeout will"
+ " likely not work\n", rv);
+ rv = 0;
+ goto out_restore;
+ }
+
+ msleep(1500);
+
+ if (testing_nmi != 2) {
+ printk(KERN_WARNING PFX "IPMI NMI didn't seem to"
+ " occur. The NMI pretimeout will"
+ " likely not work\n");
+ }
+ out_restore:
+ testing_nmi = 0;
+ preop_val = old_preop_val;
+ pretimeout = old_pretimeout;
+ timeout = old_timeout;
+ }
+#endif
+
out:
up_write(&register_sem);
@@ -928,6 +982,10 @@ static void ipmi_register_watchdog(int ipmi_intf)
ipmi_watchdog_state = action_val;
ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
printk(KERN_INFO PFX "Starting now!\n");
+ } else {
+ /* Stop the timer now. */
+ ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
+ ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
}
}
@@ -964,17 +1022,28 @@ static void ipmi_unregister_watchdog(int ipmi_intf)
up_write(&register_sem);
}
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
static int
-ipmi_nmi(void *dev_id, int cpu, int handled)
+ipmi_nmi(struct notifier_block *self, unsigned long val, void *data)
{
+ if (val != DIE_NMI_POST)
+ return NOTIFY_OK;
+
+ if (testing_nmi) {
+ testing_nmi = 2;
+ return NOTIFY_STOP;
+ }
+
/* If we are not expecting a timeout, ignore it. */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
- return NOTIFY_DONE;
+ return NOTIFY_OK;
+
+ if (preaction_val != WDOG_PRETIMEOUT_NMI)
+ return NOTIFY_OK;
/* If no one else handled the NMI, we assume it was the IPMI
watchdog. */
- if ((!handled) && (preop_val == WDOG_PREOP_PANIC)) {
+ if (preop_val == WDOG_PREOP_PANIC) {
/* On some machines, the heartbeat will give
an error and not work unless we re-enable
the timer. So do so. */
@@ -983,18 +1052,12 @@ ipmi_nmi(void *dev_id, int cpu, int handled)
panic(PFX "pre-timeout");
}
- return NOTIFY_DONE;
+ return NOTIFY_STOP;
}
-static struct nmi_handler ipmi_nmi_handler =
-{
- .link = LIST_HEAD_INIT(ipmi_nmi_handler.link),
- .dev_name = "ipmi_watchdog",
- .dev_id = NULL,
- .handler = ipmi_nmi,
- .priority = 0, /* Call us last. */
+static struct notifier_block ipmi_nmi_handler = {
+ .notifier_call = ipmi_nmi
};
-int nmi_handler_registered;
#endif
static int wdog_reboot_handler(struct notifier_block *this,
@@ -1111,7 +1174,7 @@ static int preaction_op(const char *inval, char *outval)
preaction_val = WDOG_PRETIMEOUT_NONE;
else if (strcmp(inval, "pre_smi") == 0)
preaction_val = WDOG_PRETIMEOUT_SMI;
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
else if (strcmp(inval, "pre_nmi") == 0)
preaction_val = WDOG_PRETIMEOUT_NMI;
#endif
@@ -1145,7 +1208,7 @@ static int preop_op(const char *inval, char *outval)
static void check_parms(void)
{
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
int do_nmi = 0;
int rv;
@@ -1158,20 +1221,9 @@ static void check_parms(void)
preop_op("preop_none", NULL);
do_nmi = 0;
}
-#ifdef CONFIG_X86_LOCAL_APIC
- if (nmi_watchdog == NMI_IO_APIC) {
- printk(KERN_WARNING PFX "nmi_watchdog is set to IO APIC"
- " mode (value is %d), that is incompatible"
- " with using NMI in the IPMI watchdog."
- " Disabling IPMI nmi pretimeout.\n",
- nmi_watchdog);
- preaction_val = WDOG_PRETIMEOUT_NONE;
- do_nmi = 0;
- }
-#endif
}
if (do_nmi && !nmi_handler_registered) {
- rv = request_nmi(&ipmi_nmi_handler);
+ rv = register_die_notifier(&ipmi_nmi_handler);
if (rv) {
printk(KERN_WARNING PFX
"Can't register nmi handler\n");
@@ -1179,7 +1231,7 @@ static void check_parms(void)
} else
nmi_handler_registered = 1;
} else if (!do_nmi && nmi_handler_registered) {
- release_nmi(&ipmi_nmi_handler);
+ unregister_die_notifier(&ipmi_nmi_handler);
nmi_handler_registered = 0;
}
#endif
@@ -1215,9 +1267,9 @@ static int __init ipmi_wdog_init(void)
rv = ipmi_smi_watcher_register(&smi_watcher);
if (rv) {
-#ifdef HAVE_NMI_HANDLER
- if (preaction_val == WDOG_PRETIMEOUT_NMI)
- release_nmi(&ipmi_nmi_handler);
+#ifdef HAVE_DIE_NMI_POST
+ if (nmi_handler_registered)
+ unregister_die_notifier(&ipmi_nmi_handler);
#endif
atomic_notifier_chain_unregister(&panic_notifier_list,
&wdog_panic_notifier);
@@ -1236,9 +1288,9 @@ static void __exit ipmi_wdog_exit(void)
ipmi_smi_watcher_unregister(&smi_watcher);
ipmi_unregister_watchdog(watchdog_ifnum);
-#ifdef HAVE_NMI_HANDLER
+#ifdef HAVE_DIE_NMI_POST
if (nmi_handler_registered)
- release_nmi(&ipmi_nmi_handler);
+ unregister_die_notifier(&ipmi_nmi_handler);
#endif
atomic_notifier_chain_unregister(&panic_notifier_list,
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 43ab9edc76f..761f77740d6 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -137,11 +137,10 @@
#define InterruptTheCard(base) outw(0, (base) + 0xc)
#define ClearInterrupt(base) inw((base) + 0x0a)
+#define pr_dbg(str...) pr_debug("ISICOM: " str)
#ifdef DEBUG
-#define pr_dbg(str...) printk(KERN_DEBUG "ISICOM: " str)
#define isicom_paranoia_check(a, b, c) __isicom_paranoia_check((a), (b), (c))
#else
-#define pr_dbg(str...) do { } while (0)
#define isicom_paranoia_check(a, b, c) 0
#endif
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index cb8d691576d..1b094509b1d 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -41,7 +41,6 @@
#include <linux/input.h>
#include <linux/reboot.h>
-static void kbd_disconnect(struct input_handle *handle);
extern void ctrl_alt_del(void);
/*
@@ -110,7 +109,7 @@ struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct kbd_struct *kbd = kbd_table;
struct vt_spawn_console vt_spawn_con = {
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock),
.pid = NULL,
.sig = 0,
};
@@ -159,65 +158,41 @@ static int sysrq_alt_use;
static int sysrq_alt;
/*
- * Translation of scancodes to keycodes. We set them on only the first attached
- * keyboard - for per-keyboard setting, /dev/input/event is more useful.
+ * Translation of scancodes to keycodes. We set them on only the first
+ * keyboard in the list that accepts the scancode and keycode.
+ * Explanation for not choosing the first attached keyboard anymore:
+ * USB keyboards for example have two event devices: one for all "normal"
+ * keys and one for extra function keys (like "volume up", "make coffee",
+ * etc.). So this means that scancodes for the extra function keys won't
+ * be valid for the first event device, but will be for the second.
*/
int getkeycode(unsigned int scancode)
{
- struct list_head *node;
- struct input_dev *dev = NULL;
+ struct input_handle *handle;
+ int keycode;
+ int error = -ENODEV;
- list_for_each(node, &kbd_handler.h_list) {
- struct input_handle *handle = to_handle_h(node);
- if (handle->dev->keycodesize) {
- dev = handle->dev;
- break;
- }
+ list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
+ error = handle->dev->getkeycode(handle->dev, scancode, &keycode);
+ if (!error)
+ return keycode;
}
- if (!dev)
- return -ENODEV;
-
- if (scancode >= dev->keycodemax)
- return -EINVAL;
-
- return INPUT_KEYCODE(dev, scancode);
+ return error;
}
int setkeycode(unsigned int scancode, unsigned int keycode)
{
- struct list_head *node;
- struct input_dev *dev = NULL;
- unsigned int i, oldkey;
+ struct input_handle *handle;
+ int error = -ENODEV;
- list_for_each(node, &kbd_handler.h_list) {
- struct input_handle *handle = to_handle_h(node);
- if (handle->dev->keycodesize) {
- dev = handle->dev;
+ list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
+ error = handle->dev->setkeycode(handle->dev, scancode, keycode);
+ if (!error)
break;
- }
}
- if (!dev)
- return -ENODEV;
-
- if (scancode >= dev->keycodemax)
- return -EINVAL;
- if (keycode < 0 || keycode > KEY_MAX)
- return -EINVAL;
- if (dev->keycodesize < sizeof(keycode) && (keycode >> (dev->keycodesize * 8)))
- return -EINVAL;
-
- oldkey = SET_INPUT_KEYCODE(dev, scancode, keycode);
-
- clear_bit(oldkey, dev->keybit);
- set_bit(keycode, dev->keybit);
-
- for (i = 0; i < dev->keycodemax; i++)
- if (INPUT_KEYCODE(dev,i) == oldkey)
- set_bit(oldkey, dev->keybit);
-
- return 0;
+ return error;
}
/*
@@ -225,10 +200,9 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
*/
static void kd_nosound(unsigned long ignored)
{
- struct list_head *node;
+ struct input_handle *handle;
- list_for_each(node, &kbd_handler.h_list) {
- struct input_handle *handle = to_handle_h(node);
+ list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
if (test_bit(EV_SND, handle->dev->evbit)) {
if (test_bit(SND_TONE, handle->dev->sndbit))
input_inject_event(handle, EV_SND, SND_TONE, 0);
@@ -1161,7 +1135,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
if ((raw_mode = (kbd->kbdmode == VC_RAW)) && !hw_raw)
if (emulate_raw(vc, keycode, !down << 7))
- if (keycode < BTN_MISC)
+ if (keycode < BTN_MISC && printk_ratelimit())
printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */
@@ -1285,11 +1259,11 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
* likes it, it can open it and get events from it. In this (kbd_connect)
* function, we should decide which VT to bind that keyboard to initially.
*/
-static struct input_handle *kbd_connect(struct input_handler *handler,
- struct input_dev *dev,
- const struct input_device_id *id)
+static int kbd_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct input_handle *handle;
+ int error;
int i;
for (i = KEY_RESERVED; i < BTN_MISC; i++)
@@ -1297,24 +1271,37 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
break;
if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
- return NULL;
+ return -ENODEV;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
- return NULL;
+ return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
handle->name = "kbd";
- input_open_device(handle);
+ error = input_register_handle(handle);
+ if (error)
+ goto err_free_handle;
+
+ error = input_open_device(handle);
+ if (error)
+ goto err_unregister_handle;
+
+ return 0;
- return handle;
+ err_unregister_handle:
+ input_unregister_handle(handle);
+ err_free_handle:
+ kfree(handle);
+ return error;
}
static void kbd_disconnect(struct input_handle *handle)
{
input_close_device(handle);
+ input_unregister_handle(handle);
kfree(handle);
}
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index b51d08be0bc..62051f8b091 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -118,7 +118,6 @@
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
@@ -139,9 +138,6 @@
/* if you have more than 8 printers, remember to increase LP_NO */
#define LP_NO 8
-/* ROUND_UP macro from fs/select.c */
-#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
-
static struct lp_struct lp_table[LP_NO];
static unsigned int lp_count = 0;
@@ -652,7 +648,7 @@ static int lp_ioctl(struct inode *inode, struct file *file,
(par_timeout.tv_usec < 0)) {
return -EINVAL;
}
- to_jiffies = ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
+ to_jiffies = DIV_ROUND_UP(par_timeout.tv_usec, 1000000/HZ);
to_jiffies += par_timeout.tv_sec * (long) HZ;
if (to_jiffies <= 0) {
return -EINVAL;
@@ -803,7 +799,7 @@ static int lp_register(int nr, struct parport *port)
if (reset)
lp_reset(nr);
- class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), NULL,
+ class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), port->dev,
"lp%d", nr);
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 5f066963f17..cc9a9d0df97 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -18,7 +18,6 @@
#include <linux/raw.h>
#include <linux/tty.h>
#include <linux/capability.h>
-#include <linux/smp_lock.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
@@ -552,7 +551,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
return virtr + wrote;
}
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
static ssize_t read_port(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
@@ -835,7 +834,7 @@ static const struct file_operations null_fops = {
.splice_write = splice_write_null,
};
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
static const struct file_operations port_fops = {
.llseek = memory_lseek,
.read = read_port,
@@ -913,7 +912,7 @@ static int memory_open(struct inode * inode, struct file * filp)
case 3:
filp->f_op = &null_fops;
break;
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
case 4:
filp->f_op = &port_fops;
break;
@@ -960,7 +959,7 @@ static const struct {
{1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
{2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
{3, "null", S_IRUGO | S_IWUGO, &null_fops},
-#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+#ifdef CONFIG_DEVPORT
{4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
#endif
{5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 7e975f60692..4e6fb9651a1 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -41,6 +41,7 @@
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/slab.h>
+#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
@@ -53,7 +54,7 @@
* Head entry for the doubly linked miscdevice list
*/
static LIST_HEAD(misc_list);
-static DECLARE_MUTEX(misc_sem);
+static DEFINE_MUTEX(misc_mtx);
/*
* Assigned numbers, used for dynamic minors
@@ -69,7 +70,7 @@ static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
struct miscdevice *p;
loff_t off = 0;
- down(&misc_sem);
+ mutex_lock(&misc_mtx);
list_for_each_entry(p, &misc_list, list) {
if (*pos == off++)
return p;
@@ -89,7 +90,7 @@ static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void misc_seq_stop(struct seq_file *seq, void *v)
{
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
}
static int misc_seq_show(struct seq_file *seq, void *v)
@@ -129,7 +130,7 @@ static int misc_open(struct inode * inode, struct file * file)
int err = -ENODEV;
const struct file_operations *old_fops, *new_fops = NULL;
- down(&misc_sem);
+ mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
@@ -139,9 +140,9 @@ static int misc_open(struct inode * inode, struct file * file)
}
if (!new_fops) {
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
request_module("char-major-%d-%d", MISC_MAJOR, minor);
- down(&misc_sem);
+ mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
@@ -165,7 +166,7 @@ static int misc_open(struct inode * inode, struct file * file)
}
fops_put(old_fops);
fail:
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
return err;
}
@@ -201,10 +202,10 @@ int misc_register(struct miscdevice * misc)
INIT_LIST_HEAD(&misc->list);
- down(&misc_sem);
+ mutex_lock(&misc_mtx);
list_for_each_entry(c, &misc_list, list) {
if (c->minor == misc->minor) {
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
return -EBUSY;
}
}
@@ -215,7 +216,7 @@ int misc_register(struct miscdevice * misc)
if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
break;
if (i<0) {
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
return -EBUSY;
}
misc->minor = i;
@@ -238,7 +239,7 @@ int misc_register(struct miscdevice * misc)
*/
list_add(&misc->list, &misc_list);
out:
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
return err;
}
@@ -259,13 +260,13 @@ int misc_deregister(struct miscdevice * misc)
if (list_empty(&misc->list))
return -EINVAL;
- down(&misc_sem);
+ mutex_lock(&misc_mtx);
list_del(&misc->list);
device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
if (i < DYNAMIC_MINORS && i>0) {
misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
}
- up(&misc_sem);
+ mutex_unlock(&misc_mtx);
return 0;
}
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index c09160383a5..6e55cfb9c65 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -705,15 +705,13 @@ static int __init mmtimer_init(void)
maxn++;
/* Allocate list of node ptrs to mmtimer_t's */
- timers = kmalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
+ timers = kzalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
if (timers == NULL) {
printk(KERN_ERR "%s: failed to allocate memory for device\n",
MMTIMER_NAME);
goto out3;
}
- memset(timers,0,(sizeof(mmtimer_t *)*maxn));
-
/* Allocate mmtimer_t's for each online node */
for_each_online_node(node) {
timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node);
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 7dbaee8d940..e0d35c20c04 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -1582,7 +1582,7 @@ copy:
if(copy_from_user(&dltmp, argp, sizeof(struct dl_str)))
return -EFAULT;
- if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS)
+ if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS || dltmp.len < 0)
return -EINVAL;
switch(cmd)
@@ -2529,6 +2529,8 @@ static int moxaloadbios(int cardno, unsigned char __user *tmp, int len)
void __iomem *baseAddr;
int i;
+ if(len < 0 || len > sizeof(moxaBuff))
+ return -EINVAL;
if(copy_from_user(moxaBuff, tmp, len))
return -EFAULT;
baseAddr = moxa_boards[cardno].basemem;
@@ -2576,7 +2578,7 @@ static int moxaload320b(int cardno, unsigned char __user *tmp, int len)
void __iomem *baseAddr;
int i;
- if(len > sizeof(moxaBuff))
+ if(len < 0 || len > sizeof(moxaBuff))
return -EINVAL;
if(copy_from_user(moxaBuff, tmp, len))
return -EFAULT;
@@ -2596,6 +2598,8 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len)
void __iomem *baseAddr, *ofsAddr;
int retval, port, i;
+ if(len < 0 || len > sizeof(moxaBuff))
+ return -EINVAL;
if(copy_from_user(moxaBuff, tmp, len))
return -EFAULT;
baseAddr = moxa_boards[cardno].basemem;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 80a01150b86..5953a45d7e9 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -54,7 +54,6 @@
#include <linux/gfp.h>
#include <linux/ioport.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/pci.h>
diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c
index f7603b6aeb8..6cde448cd5b 100644
--- a/drivers/char/mxser_new.c
+++ b/drivers/char/mxser_new.c
@@ -37,7 +37,6 @@
#include <linux/gfp.h>
#include <linux/ioport.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/pci.h>
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 65f2d3a96b8..14557a4822c 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -1088,13 +1088,13 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
/* block until there is a message: */
add_wait_queue(&pInfo->read_wait, &wait);
repeat:
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
pMsg = remove_msg(pInfo, pClient);
if (!pMsg && !signal_pending(current)) {
schedule();
goto repeat;
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&pInfo->read_wait, &wait);
}
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 6ac3ca4c723..b3d4ccc33a4 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -1544,21 +1544,18 @@ static unsigned int normal_poll(struct tty_struct * tty, struct file * file, pol
}
struct tty_ldisc tty_ldisc_N_TTY = {
- TTY_LDISC_MAGIC, /* magic */
- "n_tty", /* name */
- 0, /* num */
- 0, /* flags */
- n_tty_open, /* open */
- n_tty_close, /* close */
- n_tty_flush_buffer, /* flush_buffer */
- n_tty_chars_in_buffer, /* chars_in_buffer */
- read_chan, /* read */
- write_chan, /* write */
- n_tty_ioctl, /* ioctl */
- n_tty_set_termios, /* set_termios */
- normal_poll, /* poll */
- NULL, /* hangup */
- n_tty_receive_buf, /* receive_buf */
- n_tty_write_wakeup /* write_wakeup */
+ .magic = TTY_LDISC_MAGIC,
+ .name = "n_tty",
+ .open = n_tty_open,
+ .close = n_tty_close,
+ .flush_buffer = n_tty_flush_buffer,
+ .chars_in_buffer = n_tty_chars_in_buffer,
+ .read = read_chan,
+ .write = write_chan,
+ .ioctl = n_tty_ioctl,
+ .set_termios = n_tty_set_termios,
+ .poll = normal_poll,
+ .receive_buf = n_tty_receive_buf,
+ .write_wakeup = n_tty_write_wakeup
};
diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig
index 27c1179ee52..f25facd97bb 100644
--- a/drivers/char/pcmcia/Kconfig
+++ b/drivers/char/pcmcia/Kconfig
@@ -21,6 +21,7 @@ config SYNCLINK_CS
config CARDMAN_4000
tristate "Omnikey Cardman 4000 support"
depends on PCMCIA
+ select BITREVERSE
help
Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard
reader.
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index e91b43a014b..fee58e03dbe 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -31,6 +31,7 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
+#include <linux/bitrev.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -194,41 +195,17 @@ static inline unsigned char xinb(unsigned short port)
}
#endif
-#define b_0000 15
-#define b_0001 14
-#define b_0010 13
-#define b_0011 12
-#define b_0100 11
-#define b_0101 10
-#define b_0110 9
-#define b_0111 8
-#define b_1000 7
-#define b_1001 6
-#define b_1010 5
-#define b_1011 4
-#define b_1100 3
-#define b_1101 2
-#define b_1110 1
-#define b_1111 0
-
-static unsigned char irtab[16] = {
- b_0000, b_1000, b_0100, b_1100,
- b_0010, b_1010, b_0110, b_1110,
- b_0001, b_1001, b_0101, b_1101,
- b_0011, b_1011, b_0111, b_1111
-};
+static inline unsigned char invert_revert(unsigned char ch)
+{
+ return bitrev8(~ch);
+}
static void str_invert_revert(unsigned char *b, int len)
{
int i;
for (i = 0; i < len; i++)
- b[i] = (irtab[b[i] & 0x0f] << 4) | irtab[b[i] >> 4];
-}
-
-static unsigned char invert_revert(unsigned char ch)
-{
- return (irtab[ch & 0x0f] << 4) | irtab[ch >> 4];
+ b[i] = invert_revert(b[i]);
}
#define ATRLENCK(dev,pos) \
@@ -1114,7 +1091,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf,
/*
* wait for atr to become valid.
* note: it is important to lock this code. if we dont, the monitor
- * could be run between test_bit and the the call the sleep on the
+ * could be run between test_bit and the call to sleep on the
* atr-queue. if *then* the monitor detects atr valid, it will wake up
* any process on the atr-queue, *but* since we have been interrupted,
* we do not yet sleep on this queue. this would result in a missed
@@ -1881,8 +1858,11 @@ static int cm4000_probe(struct pcmcia_device *link)
init_waitqueue_head(&dev->readq);
ret = cm4000_config(link, i);
- if (ret)
+ if (ret) {
+ dev_table[i] = NULL;
+ kfree(dev);
return ret;
+ }
class_device_create(cmm_class, NULL, MKDEV(major, i), NULL,
"cmm%d", i);
@@ -1907,7 +1887,7 @@ static void cm4000_detach(struct pcmcia_device *link)
cm4000_release(link);
dev_table[devno] = NULL;
- kfree(dev);
+ kfree(dev);
class_device_destroy(cmm_class, MKDEV(major, devno));
@@ -1956,12 +1936,14 @@ static int __init cmm_init(void)
if (major < 0) {
printk(KERN_WARNING MODULE_NAME
": could not get major number\n");
+ class_destroy(cmm_class);
return major;
}
rc = pcmcia_register_driver(&cm4000_driver);
if (rc < 0) {
unregister_chrdev(major, DEVICE_NAME);
+ class_destroy(cmm_class);
return rc;
}
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index f2e4ec4fd40..af88181a17f 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -636,8 +636,11 @@ static int reader_probe(struct pcmcia_device *link)
setup_timer(&dev->poll_timer, cm4040_do_poll, 0);
ret = reader_config(link, i);
- if (ret)
+ if (ret) {
+ dev_table[i] = NULL;
+ kfree(dev);
return ret;
+ }
class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
"cmx%d", i);
@@ -708,12 +711,14 @@ static int __init cm4040_init(void)
if (major < 0) {
printk(KERN_WARNING MODULE_NAME
": could not get major number\n");
+ class_destroy(cmx_class);
return major;
}
rc = pcmcia_register_driver(&reader_driver);
if (rc < 0) {
unregister_chrdev(major, DEVICE_NAME);
+ class_destroy(cmx_class);
return rc;
}
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 157b1d09ab5..13808f6083a 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -42,7 +42,6 @@
#include <linux/timer.h>
#include <linux/time.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 4abd1eff61d..84ac64fc48a 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -66,7 +66,6 @@
#include <linux/poll.h>
#include <linux/major.h>
#include <linux/ppdev.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#include <asm/uaccess.h>
@@ -752,7 +751,7 @@ static const struct file_operations pp_fops = {
static void pp_attach(struct parport *port)
{
- device_create(ppdev_class, NULL, MKDEV(PP_MAJOR, port->number),
+ device_create(ppdev_class, port->dev, MKDEV(PP_MAJOR, port->number),
"parport%d", port->number);
}
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index 245f03195b7..8cc60b69346 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -402,7 +402,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc
rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name);
rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number 0x%x\n", rup);
- if (Rup >= (unsigned short) MAX_RUP) {
+ if (Rup < (unsigned short) MAX_RUP) {
rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name);
} else
rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name);
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 70145254fb9..3494e3fc44b 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -980,7 +980,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
}
schedule();
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&port->open_wait, &wait);
if (!tty_hung_up_p(filp))
port->count++;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 76357c855ce..a3fd7e7ba5a 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -65,10 +65,6 @@
/****** Kernel includes ******/
-#ifdef MODVERSIONS
-#include <config/modversions.h>
-#endif
-
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/major.h>
@@ -85,6 +81,7 @@
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
+#include <linux/mutex.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/wait.h>
@@ -93,7 +90,6 @@
#include <asm/atomic.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
-#include <asm/semaphore.h>
#include <linux/init.h>
/****** RocketPort includes ******/
@@ -702,7 +698,7 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
}
}
spin_lock_init(&info->slock);
- sema_init(&info->write_sem, 1);
+ mutex_init(&info->write_mtx);
rp_table[line] = info;
if (pci_dev)
tty_register_device(rocket_driver, line, &pci_dev->dev);
@@ -947,7 +943,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
#endif
schedule(); /* Don't hold spinlock here, will hang PC */
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
spin_lock_irqsave(&info->slock, flags);
@@ -1018,9 +1014,6 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
/*
* Info->count is now 1; so it's safe to sleep now.
*/
- info->session = process_session(current);
- info->pgrp = process_group(current);
-
if ((info->flags & ROCKET_INITIALIZED) == 0) {
cp = &info->channel;
sSetRxTrigger(cp, TRIG_1);
@@ -1602,7 +1595,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
if (signal_pending(current))
break;
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
#endif
@@ -1661,8 +1654,11 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch)
if (rocket_paranoia_check(info, "rp_put_char"))
return;
- /* Grab the port write semaphore, locking out other processes that try to write to this port */
- down(&info->write_sem);
+ /*
+ * Grab the port write mutex, locking out other processes that try to
+ * write to this port
+ */
+ mutex_lock(&info->write_mtx);
#ifdef ROCKET_DEBUG_WRITE
printk(KERN_INFO "rp_put_char %c...", ch);
@@ -1684,12 +1680,12 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch)
info->xmit_fifo_room--;
}
spin_unlock_irqrestore(&info->slock, flags);
- up(&info->write_sem);
+ mutex_unlock(&info->write_mtx);
}
/*
* Exception handler - write routine, called when user app writes to the device.
- * A per port write semaphore is used to protect from another process writing to
+ * A per port write mutex is used to protect from another process writing to
* this port at the same time. This other process could be running on the other CPU
* or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out).
* Spinlocks protect the info xmit members.
@@ -1706,7 +1702,7 @@ static int rp_write(struct tty_struct *tty,
if (count <= 0 || rocket_paranoia_check(info, "rp_write"))
return 0;
- down_interruptible(&info->write_sem);
+ mutex_lock_interruptible(&info->write_mtx);
#ifdef ROCKET_DEBUG_WRITE
printk(KERN_INFO "rp_write %d chars...", count);
@@ -1777,7 +1773,7 @@ end:
wake_up_interruptible(&tty->poll_wait);
#endif
}
- up(&info->write_sem);
+ mutex_unlock(&info->write_mtx);
return retval;
}
@@ -1852,6 +1848,12 @@ static void rp_flush_buffer(struct tty_struct *tty)
#ifdef CONFIG_PCI
+static struct pci_device_id __devinitdata rocket_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_RP, PCI_ANY_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, rocket_pci_ids);
+
/*
* Called when a PCI card is found. Retrieves and stores model information,
* init's aiopic and serial port hardware.
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index 3a8bcc85bc1..b4c53dfa795 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -15,6 +15,8 @@
#define ROCKET_TYPE_MODEMIII 3
#define ROCKET_TYPE_PC104 4
+#include <linux/mutex.h>
+
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -1156,8 +1158,6 @@ struct r_port {
int xmit_head;
int xmit_tail;
int xmit_cnt;
- int session;
- int pgrp;
int cd_status;
int ignore_status_mask;
int read_status_mask;
@@ -1171,7 +1171,7 @@ struct r_port {
struct wait_queue *close_wait;
#endif
spinlock_t slock;
- struct semaphore write_sem;
+ struct mutex write_mtx;
};
#define RPORT_MAGIC 0x525001
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index c7dac9b1335..20380a2c4de 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -388,7 +388,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
if (!retval)
retval = count;
out:
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&rtc_wait, &wait);
return retval;
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index 74cff839c85..a69f094d1ed 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -299,7 +299,7 @@ int paste_selection(struct tty_struct *tty)
pasted += count;
}
remove_wait_queue(&vc->paste_wait, &wait);
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
tty_ldisc_deref(ld);
return 0;
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 5fd314adc1f..c585b4738f8 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -1892,7 +1892,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
#endif
schedule();
}
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(&info->open_wait, &wait);
if (!tty_hung_up_p(filp)) {
info->count++;
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index ce4db6f5236..f02a0795983 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -4010,8 +4010,13 @@ static int mgsl_alloc_intermediate_txbuffer_memory(struct mgsl_struct *info)
for ( i=0; i<info->num_tx_holding_buffers; ++i) {
info->tx_holding_buffers[i].buffer =
kmalloc(info->max_frame_size, GFP_KERNEL);
- if ( info->tx_holding_buffers[i].buffer == NULL )
+ if (info->tx_holding_buffers[i].buffer == NULL) {
+ for (--i; i >= 0; i--) {
+ kfree(info->tx_holding_buffers[i].buffer);
+ info->tx_holding_buffers[i].buffer = NULL;
+ }
return -ENOMEM;
+ }
}
return 0;
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 0a367cd4121..02b49bc0002 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1171,6 +1171,112 @@ static int ioctl(struct tty_struct *tty, struct file *file,
}
/*
+ * support for 32 bit ioctl calls on 64 bit systems
+ */
+#ifdef CONFIG_COMPAT
+static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params)
+{
+ struct MGSL_PARAMS32 tmp_params;
+
+ DBGINFO(("%s get_params32\n", info->device_name));
+ tmp_params.mode = (compat_ulong_t)info->params.mode;
+ tmp_params.loopback = info->params.loopback;
+ tmp_params.flags = info->params.flags;
+ tmp_params.encoding = info->params.encoding;
+ tmp_params.clock_speed = (compat_ulong_t)info->params.clock_speed;
+ tmp_params.addr_filter = info->params.addr_filter;
+ tmp_params.crc_type = info->params.crc_type;
+ tmp_params.preamble_length = info->params.preamble_length;
+ tmp_params.preamble = info->params.preamble;
+ tmp_params.data_rate = (compat_ulong_t)info->params.data_rate;
+ tmp_params.data_bits = info->params.data_bits;
+ tmp_params.stop_bits = info->params.stop_bits;
+ tmp_params.parity = info->params.parity;
+ if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32)))
+ return -EFAULT;
+ return 0;
+}
+
+static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params)
+{
+ struct MGSL_PARAMS32 tmp_params;
+
+ DBGINFO(("%s set_params32\n", info->device_name));
+ if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32)))
+ return -EFAULT;
+
+ spin_lock(&info->lock);
+ info->params.mode = tmp_params.mode;
+ info->params.loopback = tmp_params.loopback;
+ info->params.flags = tmp_params.flags;
+ info->params.encoding = tmp_params.encoding;
+ info->params.clock_speed = tmp_params.clock_speed;
+ info->params.addr_filter = tmp_params.addr_filter;
+ info->params.crc_type = tmp_params.crc_type;
+ info->params.preamble_length = tmp_params.preamble_length;
+ info->params.preamble = tmp_params.preamble;
+ info->params.data_rate = tmp_params.data_rate;
+ info->params.data_bits = tmp_params.data_bits;
+ info->params.stop_bits = tmp_params.stop_bits;
+ info->params.parity = tmp_params.parity;
+ spin_unlock(&info->lock);
+
+ change_params(info);
+
+ return 0;
+}
+
+static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct slgt_info *info = tty->driver_data;
+ int rc = -ENOIOCTLCMD;
+
+ if (sanity_check(info, tty->name, "compat_ioctl"))
+ return -ENODEV;
+ DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd));
+
+ switch (cmd) {
+
+ case MGSL_IOCSPARAMS32:
+ rc = set_params32(info, compat_ptr(arg));
+ break;
+
+ case MGSL_IOCGPARAMS32:
+ rc = get_params32(info, compat_ptr(arg));
+ break;
+
+ case MGSL_IOCGPARAMS:
+ case MGSL_IOCSPARAMS:
+ case MGSL_IOCGTXIDLE:
+ case MGSL_IOCGSTATS:
+ case MGSL_IOCWAITEVENT:
+ case MGSL_IOCGIF:
+ case MGSL_IOCSGPIO:
+ case MGSL_IOCGGPIO:
+ case MGSL_IOCWAITGPIO:
+ case TIOCGICOUNT:
+ rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg)));
+ break;
+
+ case MGSL_IOCSTXIDLE:
+ case MGSL_IOCTXENABLE:
+ case MGSL_IOCRXENABLE:
+ case MGSL_IOCTXABORT:
+ case TIOCMIWAIT:
+ case MGSL_IOCSIF:
+ rc = ioctl(tty, file, cmd, arg);
+ break;
+ }
+
+ DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc));
+ return rc;
+}
+#else
+#define slgt_compat_ioctl NULL
+#endif /* ifdef CONFIG_COMPAT */
+
+/*
* proc fs support
*/
static inline int line_info(char *buf, struct slgt_info *info)
@@ -3415,6 +3521,9 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
}
}
}
+
+ for (i=0; i < port_count; ++i)
+ tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev));
}
static int __devinit init_one(struct pci_dev *dev,
@@ -3443,6 +3552,7 @@ static const struct tty_operations ops = {
.chars_in_buffer = chars_in_buffer,
.flush_buffer = flush_buffer,
.ioctl = ioctl,
+ .compat_ioctl = slgt_compat_ioctl,
.throttle = throttle,
.unthrottle = unthrottle,
.send_xchar = send_xchar,
@@ -3466,6 +3576,8 @@ static void slgt_cleanup(void)
printk("unload %s %s\n", driver_name, driver_version);
if (serial_driver) {
+ for (info=slgt_device_list ; info != NULL ; info=info->next_device)
+ tty_unregister_device(serial_driver, info->line);
if ((rc = tty_unregister_driver(serial_driver)))
DBGERR(("tty_unregister_driver error=%d\n", rc));
put_tty_driver(serial_driver);
@@ -3506,23 +3618,10 @@ static int __init slgt_init(void)
printk("%s %s\n", driver_name, driver_version);
- slgt_device_count = 0;
- if ((rc = pci_register_driver(&pci_driver)) < 0) {
- printk("%s pci_register_driver error=%d\n", driver_name, rc);
- return rc;
- }
- pci_registered = 1;
-
- if (!slgt_device_list) {
- printk("%s no devices found\n",driver_name);
- pci_unregister_driver(&pci_driver);
- return -ENODEV;
- }
-
serial_driver = alloc_tty_driver(MAX_DEVICES);
if (!serial_driver) {
- rc = -ENOMEM;
- goto error;
+ printk("%s can't allocate tty driver\n", driver_name);
+ return -ENOMEM;
}
/* Initialize the tty_driver structure */
@@ -3539,7 +3638,7 @@ static int __init slgt_init(void)
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
serial_driver->init_termios.c_ispeed = 9600;
serial_driver->init_termios.c_ospeed = 9600;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
+ serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(serial_driver, &ops);
if ((rc = tty_register_driver(serial_driver)) < 0) {
DBGERR(("%s can't register serial driver\n", driver_name));
@@ -3552,6 +3651,16 @@ static int __init slgt_init(void)
driver_name, driver_version,
serial_driver->major);
+ slgt_device_count = 0;
+ if ((rc = pci_register_driver(&pci_driver)) < 0) {
+ printk("%s pci_register_driver error=%d\n", driver_name, rc);
+ goto error;
+ }
+ pci_registered = 1;
+
+ if (!slgt_device_list)
+ printk("%s no devices found\n",driver_name);
+
return 0;
error:
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 1d8c4ae6155..39cc318011e 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -24,7 +24,6 @@
#include <linux/sysrq.h>
#include <linux/kbd_kern.h>
#include <linux/quotaops.h>
-#include <linux/smp_lock.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/suspend.h>
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 47fb20f6969..35b40b99653 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -442,7 +442,7 @@ tipar_register(int nr, struct parport *port)
}
class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
- TIPAR_MINOR + nr), NULL, "par%d", nr);
+ TIPAR_MINOR + nr), port->dev, "par%d", nr);
/* Display informations */
pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index fe00c7dfb64..dc4e1ff7f56 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -3,6 +3,7 @@
#
menu "TPM devices"
+ depends on HAS_IOMEM
config TCG_TPM
tristate "TPM Hardware Support"
@@ -33,7 +34,7 @@ config TCG_NSC
tristate "National Semiconductor TPM Interface"
depends on TCG_TPM && PNPACPI
---help---
- If you have a TPM security chip from National Semicondutor
+ If you have a TPM security chip from National Semiconductor
say Yes and it will be accessible from within Linux. To
compile this driver as a module, choose M here; the module
will be called tpm_nsc.
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index e5a254a434f..9bb542913b8 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -24,7 +24,9 @@
*/
#include <linux/poll.h>
+#include <linux/mutex.h>
#include <linux/spinlock.h>
+
#include "tpm.h"
enum tpm_const {
@@ -328,10 +330,10 @@ static void timeout_work(struct work_struct *work)
{
struct tpm_chip *chip = container_of(work, struct tpm_chip, work);
- down(&chip->buffer_mutex);
+ mutex_lock(&chip->buffer_mutex);
atomic_set(&chip->data_pending, 0);
memset(chip->data_buffer, 0, TPM_BUFSIZE);
- up(&chip->buffer_mutex);
+ mutex_unlock(&chip->buffer_mutex);
}
/*
@@ -380,7 +382,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
return -E2BIG;
}
- down(&chip->tpm_mutex);
+ mutex_lock(&chip->tpm_mutex);
if ((rc = chip->vendor.send(chip, (u8 *) buf, count)) < 0) {
dev_err(chip->dev,
@@ -419,7 +421,7 @@ out_recv:
dev_err(chip->dev,
"tpm_transmit: tpm_recv: error %zd\n", rc);
out:
- up(&chip->tpm_mutex);
+ mutex_unlock(&chip->tpm_mutex);
return rc;
}
@@ -942,12 +944,12 @@ int tpm_release(struct inode *inode, struct file *file)
{
struct tpm_chip *chip = file->private_data;
+ flush_scheduled_work();
spin_lock(&driver_lock);
file->private_data = NULL;
- chip->num_opens--;
del_singleshot_timer_sync(&chip->user_read_timer);
- flush_scheduled_work();
atomic_set(&chip->data_pending, 0);
+ chip->num_opens--;
put_device(chip->dev);
kfree(chip->data_buffer);
spin_unlock(&driver_lock);
@@ -966,14 +968,14 @@ ssize_t tpm_write(struct file *file, const char __user *buf,
while (atomic_read(&chip->data_pending) != 0)
msleep(TPM_TIMEOUT);
- down(&chip->buffer_mutex);
+ mutex_lock(&chip->buffer_mutex);
if (in_size > TPM_BUFSIZE)
in_size = TPM_BUFSIZE;
if (copy_from_user
(chip->data_buffer, (void __user *) buf, in_size)) {
- up(&chip->buffer_mutex);
+ mutex_unlock(&chip->buffer_mutex);
return -EFAULT;
}
@@ -981,7 +983,7 @@ ssize_t tpm_write(struct file *file, const char __user *buf,
out_size = tpm_transmit(chip, chip->data_buffer, TPM_BUFSIZE);
atomic_set(&chip->data_pending, out_size);
- up(&chip->buffer_mutex);
+ mutex_unlock(&chip->buffer_mutex);
/* Set a timeout by which the reader must come claim the result */
mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
@@ -1004,10 +1006,10 @@ ssize_t tpm_read(struct file *file, char __user *buf,
if (size < ret_size)
ret_size = size;
- down(&chip->buffer_mutex);
+ mutex_lock(&chip->buffer_mutex);
if (copy_to_user(buf, chip->data_buffer, ret_size))
ret_size = -EFAULT;
- up(&chip->buffer_mutex);
+ mutex_unlock(&chip->buffer_mutex);
}
return ret_size;
@@ -1097,11 +1099,16 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
/* Driver specific per-device data */
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (chip == NULL)
+ devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
+
+ if (chip == NULL || devname == NULL) {
+ kfree(chip);
+ kfree(devname);
return NULL;
+ }
- init_MUTEX(&chip->buffer_mutex);
- init_MUTEX(&chip->tpm_mutex);
+ mutex_init(&chip->buffer_mutex);
+ mutex_init(&chip->tpm_mutex);
INIT_LIST_HEAD(&chip->list);
INIT_WORK(&chip->work, timeout_work);
@@ -1124,7 +1131,6 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
set_bit(chip->dev_num, dev_mask);
- devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
chip->vendor.miscdev.name = devname;
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index bb9a43c6cf3..b2e2b002a1b 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -19,9 +19,9 @@
*
*/
#include <linux/module.h>
-#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/fs.h>
+#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
@@ -95,11 +95,11 @@ struct tpm_chip {
/* Data passed to and from the tpm via the read/write calls */
u8 *data_buffer;
atomic_t data_pending;
- struct semaphore buffer_mutex;
+ struct mutex buffer_mutex;
struct timer_list user_read_timer; /* user needs to claim result */
struct work_struct work;
- struct semaphore tpm_mutex; /* tpm is processing */
+ struct mutex tpm_mutex; /* tpm is processing */
struct tpm_vendor_specific vendor;
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
index 3c852009196..c912d8691cb 100644
--- a/drivers/char/tpm/tpm_atmel.h
+++ b/drivers/char/tpm/tpm_atmel.h
@@ -47,12 +47,12 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size)
if (!dn)
return NULL;
- if (!device_is_compatible(dn, "AT97SC3201")) {
+ if (!of_device_is_compatible(dn, "AT97SC3201")) {
of_node_put(dn);
return NULL;
}
- reg = get_property(dn, "reg", &reglen);
+ reg = of_get_property(dn, "reg", &reglen);
naddrc = of_n_addr_cells(dn);
nsizec = of_n_size_cells(dn);
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index 1353b5a6bae..967002a5a1e 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -30,12 +30,60 @@
#define TPM_MAX_TRIES 5000
#define TPM_INFINEON_DEV_VEN_VALUE 0x15D1
-/* These values will be filled after PnP-call */
-static int TPM_INF_DATA;
-static int TPM_INF_ADDR;
-static int TPM_INF_BASE;
-static int TPM_INF_ADDR_LEN;
-static int TPM_INF_PORT_LEN;
+#define TPM_INF_IO_PORT 0x0
+#define TPM_INF_IO_MEM 0x1
+
+#define TPM_INF_ADDR 0x0
+#define TPM_INF_DATA 0x1
+
+struct tpm_inf_dev {
+ int iotype;
+
+ void __iomem *mem_base; /* MMIO ioremap'd addr */
+ unsigned long map_base; /* phys MMIO base */
+ unsigned long map_size; /* MMIO region size */
+ unsigned int index_off; /* index register offset */
+
+ unsigned int data_regs; /* Data registers */
+ unsigned int data_size;
+
+ unsigned int config_port; /* IO Port config index reg */
+ unsigned int config_size;
+};
+
+static struct tpm_inf_dev tpm_dev;
+
+static inline void tpm_data_out(unsigned char data, unsigned char offset)
+{
+ if (tpm_dev.iotype == TPM_INF_IO_PORT)
+ outb(data, tpm_dev.data_regs + offset);
+ else
+ writeb(data, tpm_dev.mem_base + tpm_dev.data_regs + offset);
+}
+
+static inline unsigned char tpm_data_in(unsigned char offset)
+{
+ if (tpm_dev.iotype == TPM_INF_IO_PORT)
+ return inb(tpm_dev.data_regs + offset);
+ else
+ return readb(tpm_dev.mem_base + tpm_dev.data_regs + offset);
+}
+
+static inline void tpm_config_out(unsigned char data, unsigned char offset)
+{
+ if (tpm_dev.iotype == TPM_INF_IO_PORT)
+ outb(data, tpm_dev.config_port + offset);
+ else
+ writeb(data, tpm_dev.mem_base + tpm_dev.index_off + offset);
+}
+
+static inline unsigned char tpm_config_in(unsigned char offset)
+{
+ if (tpm_dev.iotype == TPM_INF_IO_PORT)
+ return inb(tpm_dev.config_port + offset);
+ else
+ return readb(tpm_dev.mem_base + tpm_dev.index_off + offset);
+}
/* TPM header definitions */
enum infineon_tpm_header {
@@ -105,7 +153,7 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
if (clear_wrfifo) {
for (i = 0; i < 4096; i++) {
- status = inb(chip->vendor.base + WRFIFO);
+ status = tpm_data_in(WRFIFO);
if (status == 0xff) {
if (check == 5)
break;
@@ -125,8 +173,8 @@ static int empty_fifo(struct tpm_chip *chip, int clear_wrfifo)
*/
i = 0;
do {
- status = inb(chip->vendor.base + RDFIFO);
- status = inb(chip->vendor.base + STAT);
+ status = tpm_data_in(RDFIFO);
+ status = tpm_data_in(STAT);
i++;
if (i == TPM_MAX_TRIES)
return -EIO;
@@ -139,7 +187,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
int status;
int i;
for (i = 0; i < TPM_MAX_TRIES; i++) {
- status = inb(chip->vendor.base + STAT);
+ status = tpm_data_in(STAT);
/* check the status-register if wait_for_bit is set */
if (status & 1 << wait_for_bit)
break;
@@ -158,7 +206,7 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
{
wait(chip, STAT_XFE);
- outb(sendbyte, chip->vendor.base + WRFIFO);
+ tpm_data_out(sendbyte, WRFIFO);
}
/* Note: WTX means Waiting-Time-Extension. Whenever the TPM needs more
@@ -205,7 +253,7 @@ recv_begin:
ret = wait(chip, STAT_RDA);
if (ret)
return -EIO;
- buf[i] = inb(chip->vendor.base + RDFIFO);
+ buf[i] = tpm_data_in(RDFIFO);
}
if (buf[0] != TPM_VL_VER) {
@@ -220,7 +268,7 @@ recv_begin:
for (i = 0; i < size; i++) {
wait(chip, STAT_RDA);
- buf[i] = inb(chip->vendor.base + RDFIFO);
+ buf[i] = tpm_data_in(RDFIFO);
}
if ((size == 0x6D00) && (buf[1] == 0x80)) {
@@ -269,7 +317,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
u8 count_high, count_low, count_4, count_3, count_2, count_1;
/* Disabling Reset, LP and IRQC */
- outb(RESET_LP_IRQC_DISABLE, chip->vendor.base + CMD);
+ tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
ret = empty_fifo(chip, 1);
if (ret) {
@@ -320,7 +368,7 @@ static void tpm_inf_cancel(struct tpm_chip *chip)
static u8 tpm_inf_status(struct tpm_chip *chip)
{
- return inb(chip->vendor.base + STAT);
+ return tpm_data_in(STAT);
}
static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
@@ -381,51 +429,88 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
/* read IO-ports through PnP */
if (pnp_port_valid(dev, 0) && pnp_port_valid(dev, 1) &&
!(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) {
- TPM_INF_ADDR = pnp_port_start(dev, 0);
- TPM_INF_ADDR_LEN = pnp_port_len(dev, 0);
- TPM_INF_DATA = (TPM_INF_ADDR + 1);
- TPM_INF_BASE = pnp_port_start(dev, 1);
- TPM_INF_PORT_LEN = pnp_port_len(dev, 1);
- if ((TPM_INF_PORT_LEN < 4) || (TPM_INF_ADDR_LEN < 2)) {
+
+ tpm_dev.iotype = TPM_INF_IO_PORT;
+
+ tpm_dev.config_port = pnp_port_start(dev, 0);
+ tpm_dev.config_size = pnp_port_len(dev, 0);
+ tpm_dev.data_regs = pnp_port_start(dev, 1);
+ tpm_dev.data_size = pnp_port_len(dev, 1);
+ if ((tpm_dev.data_size < 4) || (tpm_dev.config_size < 2)) {
rc = -EINVAL;
goto err_last;
}
dev_info(&dev->dev, "Found %s with ID %s\n",
dev->name, dev_id->id);
- if (!((TPM_INF_BASE >> 8) & 0xff)) {
+ if (!((tpm_dev.data_regs >> 8) & 0xff)) {
rc = -EINVAL;
goto err_last;
}
/* publish my base address and request region */
- if (request_region
- (TPM_INF_BASE, TPM_INF_PORT_LEN, "tpm_infineon0") == NULL) {
+ if (request_region(tpm_dev.data_regs, tpm_dev.data_size,
+ "tpm_infineon0") == NULL) {
rc = -EINVAL;
goto err_last;
}
- if (request_region
- (TPM_INF_ADDR, TPM_INF_ADDR_LEN, "tpm_infineon0") == NULL) {
+ if (request_region(tpm_dev.config_port, tpm_dev.config_size,
+ "tpm_infineon0") == NULL) {
+ release_region(tpm_dev.data_regs, tpm_dev.data_size);
rc = -EINVAL;
goto err_last;
}
+ } else if (pnp_mem_valid(dev, 0) &&
+ !(pnp_mem_flags(dev, 0) & IORESOURCE_DISABLED)) {
+
+ tpm_dev.iotype = TPM_INF_IO_MEM;
+
+ tpm_dev.map_base = pnp_mem_start(dev, 0);
+ tpm_dev.map_size = pnp_mem_len(dev, 0);
+
+ dev_info(&dev->dev, "Found %s with ID %s\n",
+ dev->name, dev_id->id);
+
+ /* publish my base address and request region */
+ if (request_mem_region(tpm_dev.map_base, tpm_dev.map_size,
+ "tpm_infineon0") == NULL) {
+ rc = -EINVAL;
+ goto err_last;
+ }
+
+ tpm_dev.mem_base = ioremap(tpm_dev.map_base, tpm_dev.map_size);
+ if (tpm_dev.mem_base == NULL) {
+ release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
+ rc = -EINVAL;
+ goto err_last;
+ }
+
+ /*
+ * The only known MMIO based Infineon TPM system provides
+ * a single large mem region with the device config
+ * registers at the default TPM_ADDR. The data registers
+ * seem like they could be placed anywhere within the MMIO
+ * region, but lets just put them at zero offset.
+ */
+ tpm_dev.index_off = TPM_ADDR;
+ tpm_dev.data_regs = 0x0;
} else {
rc = -EINVAL;
goto err_last;
}
/* query chip for its vendor, its version number a.s.o. */
- outb(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
- outb(IDVENL, TPM_INF_ADDR);
- vendorid[1] = inb(TPM_INF_DATA);
- outb(IDVENH, TPM_INF_ADDR);
- vendorid[0] = inb(TPM_INF_DATA);
- outb(IDPDL, TPM_INF_ADDR);
- productid[1] = inb(TPM_INF_DATA);
- outb(IDPDH, TPM_INF_ADDR);
- productid[0] = inb(TPM_INF_DATA);
- outb(CHIP_ID1, TPM_INF_ADDR);
- version[1] = inb(TPM_INF_DATA);
- outb(CHIP_ID2, TPM_INF_ADDR);
- version[0] = inb(TPM_INF_DATA);
+ tpm_config_out(ENABLE_REGISTER_PAIR, TPM_INF_ADDR);
+ tpm_config_out(IDVENL, TPM_INF_ADDR);
+ vendorid[1] = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(IDVENH, TPM_INF_ADDR);
+ vendorid[0] = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(IDPDL, TPM_INF_ADDR);
+ productid[1] = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(IDPDH, TPM_INF_ADDR);
+ productid[0] = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(CHIP_ID1, TPM_INF_ADDR);
+ version[1] = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(CHIP_ID2, TPM_INF_ADDR);
+ version[0] = tpm_config_in(TPM_INF_DATA);
switch ((productid[0] << 8) | productid[1]) {
case 6:
@@ -442,51 +527,54 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
if ((vendorid[0] << 8 | vendorid[1]) == (TPM_INFINEON_DEV_VEN_VALUE)) {
/* configure TPM with IO-ports */
- outb(IOLIMH, TPM_INF_ADDR);
- outb(((TPM_INF_BASE >> 8) & 0xff), TPM_INF_DATA);
- outb(IOLIML, TPM_INF_ADDR);
- outb((TPM_INF_BASE & 0xff), TPM_INF_DATA);
+ tpm_config_out(IOLIMH, TPM_INF_ADDR);
+ tpm_config_out((tpm_dev.data_regs >> 8) & 0xff, TPM_INF_DATA);
+ tpm_config_out(IOLIML, TPM_INF_ADDR);
+ tpm_config_out((tpm_dev.data_regs & 0xff), TPM_INF_DATA);
/* control if IO-ports are set correctly */
- outb(IOLIMH, TPM_INF_ADDR);
- ioh = inb(TPM_INF_DATA);
- outb(IOLIML, TPM_INF_ADDR);
- iol = inb(TPM_INF_DATA);
+ tpm_config_out(IOLIMH, TPM_INF_ADDR);
+ ioh = tpm_config_in(TPM_INF_DATA);
+ tpm_config_out(IOLIML, TPM_INF_ADDR);
+ iol = tpm_config_in(TPM_INF_DATA);
- if ((ioh << 8 | iol) != TPM_INF_BASE) {
+ if ((ioh << 8 | iol) != tpm_dev.data_regs) {
dev_err(&dev->dev,
- "Could not set IO-ports to 0x%x\n",
- TPM_INF_BASE);
+ "Could not set IO-data registers to 0x%x\n",
+ tpm_dev.data_regs);
rc = -EIO;
goto err_release_region;
}
/* activate register */
- outb(TPM_DAR, TPM_INF_ADDR);
- outb(0x01, TPM_INF_DATA);
- outb(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
+ tpm_config_out(TPM_DAR, TPM_INF_ADDR);
+ tpm_config_out(0x01, TPM_INF_DATA);
+ tpm_config_out(DISABLE_REGISTER_PAIR, TPM_INF_ADDR);
/* disable RESET, LP and IRQC */
- outb(RESET_LP_IRQC_DISABLE, TPM_INF_BASE + CMD);
+ tpm_data_out(RESET_LP_IRQC_DISABLE, CMD);
/* Finally, we're done, print some infos */
dev_info(&dev->dev, "TPM found: "
- "config base 0x%x, "
- "io base 0x%x, "
+ "config base 0x%lx, "
+ "data base 0x%lx, "
"chip version 0x%02x%02x, "
"vendor id 0x%x%x (Infineon), "
"product id 0x%02x%02x"
"%s\n",
- TPM_INF_ADDR,
- TPM_INF_BASE,
+ tpm_dev.iotype == TPM_INF_IO_PORT ?
+ tpm_dev.config_port :
+ tpm_dev.map_base + tpm_dev.index_off,
+ tpm_dev.iotype == TPM_INF_IO_PORT ?
+ tpm_dev.data_regs :
+ tpm_dev.map_base + tpm_dev.data_regs,
version[0], version[1],
vendorid[0], vendorid[1],
productid[0], productid[1], chipname);
- if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf))) {
+ if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
goto err_release_region;
- }
- chip->vendor.base = TPM_INF_BASE;
+
return 0;
} else {
rc = -ENODEV;
@@ -494,8 +582,13 @@ static int __devinit tpm_inf_pnp_probe(struct pnp_dev *dev,
}
err_release_region:
- release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
- release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
+ if (tpm_dev.iotype == TPM_INF_IO_PORT) {
+ release_region(tpm_dev.data_regs, tpm_dev.data_size);
+ release_region(tpm_dev.config_port, tpm_dev.config_size);
+ } else {
+ iounmap(tpm_dev.mem_base);
+ release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
+ }
err_last:
return rc;
@@ -506,8 +599,14 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
struct tpm_chip *chip = pnp_get_drvdata(dev);
if (chip) {
- release_region(TPM_INF_BASE, TPM_INF_PORT_LEN);
- release_region(TPM_INF_ADDR, TPM_INF_ADDR_LEN);
+ if (tpm_dev.iotype == TPM_INF_IO_PORT) {
+ release_region(tpm_dev.data_regs, tpm_dev.data_size);
+ release_region(tpm_dev.config_port,
+ tpm_dev.config_size);
+ } else {
+ iounmap(tpm_dev.mem_base);
+ release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
+ }
tpm_remove_hardware(chip->dev);
}
}
@@ -539,5 +638,5 @@ module_exit(cleanup_inf);
MODULE_AUTHOR("Marcel Selhorst <selhorst@crypto.rub.de>");
MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
-MODULE_VERSION("1.8");
+MODULE_VERSION("1.9");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 7a32df59490..fe62c2170d0 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -141,8 +141,6 @@ static DECLARE_MUTEX(allocated_ptys_lock);
static int ptmx_open(struct inode *, struct file *);
#endif
-extern void disable_early_printk(void);
-
static void initialize_tty_struct(struct tty_struct *tty);
static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
@@ -153,10 +151,16 @@ static int tty_open(struct inode *, struct file *);
static int tty_release(struct inode *, struct file *);
int tty_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+ unsigned long arg);
+#else
+#define tty_compat_ioctl NULL
+#endif
static int tty_fasync(int fd, struct file * filp, int on);
static void release_tty(struct tty_struct *tty, int idx);
-static struct pid *__proc_set_tty(struct task_struct *tsk,
- struct tty_struct *tty);
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty);
/**
* alloc_tty_struct - allocate a tty object
@@ -936,13 +940,6 @@ restart:
return -EINVAL;
/*
- * No more input please, we are switching. The new ldisc
- * will update this value in the ldisc open function
- */
-
- tty->receive_room = 0;
-
- /*
* Problem: What do we do if this blocks ?
*/
@@ -953,6 +950,13 @@ restart:
return 0;
}
+ /*
+ * No more input please, we are switching. The new ldisc
+ * will update this value in the ldisc open function
+ */
+
+ tty->receive_room = 0;
+
o_ldisc = tty->ldisc;
o_tty = tty->link;
@@ -1145,8 +1149,8 @@ static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait)
return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
}
-static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg)
+static long hung_up_tty_ioctl(struct file * file,
+ unsigned int cmd, unsigned long arg)
{
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
@@ -1157,6 +1161,7 @@ static const struct file_operations tty_fops = {
.write = tty_write,
.poll = tty_poll,
.ioctl = tty_ioctl,
+ .compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
@@ -1169,6 +1174,7 @@ static const struct file_operations ptmx_fops = {
.write = tty_write,
.poll = tty_poll,
.ioctl = tty_ioctl,
+ .compat_ioctl = tty_compat_ioctl,
.open = ptmx_open,
.release = tty_release,
.fasync = tty_fasync,
@@ -1181,6 +1187,7 @@ static const struct file_operations console_fops = {
.write = redirected_tty_write,
.poll = tty_poll,
.ioctl = tty_ioctl,
+ .compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
.fasync = tty_fasync,
@@ -1191,7 +1198,8 @@ static const struct file_operations hung_up_tty_fops = {
.read = hung_up_tty_read,
.write = hung_up_tty_write,
.poll = hung_up_tty_poll,
- .ioctl = hung_up_tty_ioctl,
+ .unlocked_ioctl = hung_up_tty_ioctl,
+ .compat_ioctl = hung_up_tty_ioctl,
.release = tty_release,
};
@@ -1534,10 +1542,9 @@ void disassociate_ctty(int on_exit)
}
spin_lock_irq(&current->sighand->siglock);
- tty_pgrp = current->signal->tty_old_pgrp;
+ put_pid(current->signal->tty_old_pgrp);
current->signal->tty_old_pgrp = NULL;
spin_unlock_irq(&current->sighand->siglock);
- put_pid(tty_pgrp);
mutex_lock(&tty_mutex);
/* It is possible that do_tty_hangup has free'd this tty */
@@ -1562,13 +1569,25 @@ void disassociate_ctty(int on_exit)
unlock_kernel();
}
+/**
+ *
+ * no_tty - Ensure the current process does not have a controlling tty
+ */
+void no_tty(void)
+{
+ struct task_struct *tsk = current;
+ if (tsk->signal->leader)
+ disassociate_ctty(0);
+ proc_clear_tty(tsk);
+}
+
/**
- * stop_tty - propogate flow control
+ * stop_tty - propagate flow control
* @tty: tty to stop
*
* Perform flow control to the driver. For PTY/TTY pairs we
- * must also propogate the TIOCKPKT status. May be called
+ * must also propagate the TIOCKPKT status. May be called
* on an already stopped device and will not re-call the driver
* method.
*
@@ -1598,11 +1617,11 @@ void stop_tty(struct tty_struct *tty)
EXPORT_SYMBOL(stop_tty);
/**
- * start_tty - propogate flow control
+ * start_tty - propagate flow control
* @tty: tty to start
*
* Start a tty that has been stopped if at all possible. Perform
- * any neccessary wakeups and propogate the TIOCPKT status. If this
+ * any neccessary wakeups and propagate the TIOCPKT status. If this
* is the tty was previous stopped and is being started then the
* driver start method is invoked and the line discipline woken.
*
@@ -2508,7 +2527,6 @@ static int tty_open(struct inode * inode, struct file * filp)
int index;
dev_t device = inode->i_rdev;
unsigned short saved_flags = filp->f_flags;
- struct pid *old_pgrp;
nonseekable_open(inode, filp);
@@ -2602,17 +2620,15 @@ got_driver:
goto retry_open;
}
- old_pgrp = NULL;
mutex_lock(&tty_mutex);
spin_lock_irq(&current->sighand->siglock);
if (!noctty &&
current->signal->leader &&
!current->signal->tty &&
tty->session == NULL)
- old_pgrp = __proc_set_tty(current, tty);
+ __proc_set_tty(current, tty);
spin_unlock_irq(&current->sighand->siglock);
mutex_unlock(&tty_mutex);
- put_pid(old_pgrp);
return 0;
}
@@ -3287,9 +3303,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
case TIOCNOTTY:
if (current->signal->tty != tty)
return -ENOTTY;
- if (current->signal->leader)
- disassociate_ctty(0);
- proc_clear_tty(current);
+ no_tty();
return 0;
case TIOCSCTTY:
return tiocsctty(tty, arg);
@@ -3353,6 +3367,32 @@ int tty_ioctl(struct inode * inode, struct file * file,
return retval;
}
+#ifdef CONFIG_COMPAT
+static long tty_compat_ioctl(struct file * file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct tty_struct *tty = file->private_data;
+ struct tty_ldisc *ld;
+ int retval = -ENOIOCTLCMD;
+
+ if (tty_paranoia_check(tty, inode, "tty_ioctl"))
+ return -EINVAL;
+
+ if (tty->driver->compat_ioctl) {
+ retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg);
+ if (retval != -ENOIOCTLCMD)
+ return retval;
+ }
+
+ ld = tty_ldisc_ref_wait(tty);
+ if (ld->compat_ioctl)
+ retval = ld->compat_ioctl(tty, file, cmd, arg);
+ tty_ldisc_deref(ld);
+
+ return retval;
+}
+#endif
/*
* This implements the "Secure Attention Key" --- the idea is to
@@ -3685,6 +3725,7 @@ void tty_set_operations(struct tty_driver *driver,
driver->write_room = op->write_room;
driver->chars_in_buffer = op->chars_in_buffer;
driver->ioctl = op->ioctl;
+ driver->compat_ioctl = op->compat_ioctl;
driver->set_termios = op->set_termios;
driver->throttle = op->throttle;
driver->unthrottle = op->unthrottle;
@@ -3720,11 +3761,10 @@ int tty_register_driver(struct tty_driver *driver)
if (driver->flags & TTY_DRIVER_INSTALLED)
return 0;
- if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
- p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
+ if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
+ p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
if (!p)
return -ENOMEM;
- memset(p, 0, driver->num * 3 * sizeof(void *));
}
if (!driver->major) {
@@ -3767,7 +3807,9 @@ int tty_register_driver(struct tty_driver *driver)
if (!driver->put_char)
driver->put_char = tty_default_put_char;
+ mutex_lock(&tty_mutex);
list_add(&driver->tty_drivers, &tty_drivers);
+ mutex_unlock(&tty_mutex);
if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) {
for(i = 0; i < driver->num; i++)
@@ -3793,8 +3835,9 @@ int tty_unregister_driver(struct tty_driver *driver)
unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
driver->num);
-
+ mutex_lock(&tty_mutex);
list_del(&driver->tty_drivers);
+ mutex_unlock(&tty_mutex);
/*
* Free the termios and termios_locked structures because
@@ -3837,11 +3880,9 @@ void proc_clear_tty(struct task_struct *p)
p->signal->tty = NULL;
spin_unlock_irq(&p->sighand->siglock);
}
-EXPORT_SYMBOL(proc_clear_tty);
-static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
{
- struct pid *old_pgrp;
if (tty) {
/* We should not have a session or pgrp to here but.... */
put_pid(tty->session);
@@ -3849,21 +3890,16 @@ static struct pid *__proc_set_tty(struct task_struct *tsk, struct tty_struct *tt
tty->session = get_pid(task_session(tsk));
tty->pgrp = get_pid(task_pgrp(tsk));
}
- old_pgrp = tsk->signal->tty_old_pgrp;
+ put_pid(tsk->signal->tty_old_pgrp);
tsk->signal->tty = tty;
tsk->signal->tty_old_pgrp = NULL;
- return old_pgrp;
}
-void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
+static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
{
- struct pid *old_pgrp;
-
spin_lock_irq(&tsk->sighand->siglock);
- old_pgrp = __proc_set_tty(tsk, tty);
+ __proc_set_tty(tsk, tty);
spin_unlock_irq(&tsk->sighand->siglock);
-
- put_pid(old_pgrp);
}
struct tty_struct *get_current_tty(void)
@@ -3898,9 +3934,6 @@ void __init console_init(void)
* set up the console device so that later boot sequences can
* inform about problems etc..
*/
-#ifdef CONFIG_EARLY_PRINTK
- disable_early_printk();
-#endif
call = __con_initcall_start;
while (call < __con_initcall_end) {
(*call)();
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index 791930320a1..83aeedda200 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -28,12 +28,13 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/mutex.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/kbd_kern.h>
#include <linux/console.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
+
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
@@ -70,11 +71,11 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
{
int size;
- down(&con_buf_sem);
+ mutex_lock(&con_buf_mtx);
size = vcs_size(file->f_path.dentry->d_inode);
switch (orig) {
default:
- up(&con_buf_sem);
+ mutex_unlock(&con_buf_mtx);
return -EINVAL;
case 2:
offset += size;
@@ -85,11 +86,11 @@ static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
break;
}
if (offset < 0 || offset > size) {
- up(&con_buf_sem);
+ mutex_unlock(&con_buf_mtx);
return -EINVAL;
}
file->f_pos = offset;
- up(&con_buf_sem);
+ mutex_unlock(&con_buf_mtx);
return file->f_pos;
}
@@ -106,7 +107,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
unsigned short *org = NULL;
ssize_t ret;
- down(&con_buf_sem);
+ mutex_lock(&con_buf_mtx);
pos = *ppos;
@@ -263,7 +264,7 @@ vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
ret = read;
unlock_out:
release_console_sem();
- up(&con_buf_sem);
+ mutex_unlock(&con_buf_mtx);
return ret;
}
@@ -280,7 +281,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
u16 *org0 = NULL, *org = NULL;
size_t ret;
- down(&con_buf_sem);
+ mutex_lock(&con_buf_mtx);
pos = *ppos;
@@ -450,7 +451,7 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
unlock_out:
release_console_sem();
- up(&con_buf_sem);
+ mutex_unlock(&con_buf_mtx);
return ret;
}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 1bbb45b937f..bbd9fc41287 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -86,6 +86,7 @@
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/init.h>
+#include <linux/mutex.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/tiocl.h>
@@ -157,6 +158,8 @@ static void blank_screen_t(unsigned long dummy);
static void set_palette(struct vc_data *vc);
static int printable; /* Is console ready for printing? */
+static int default_utf8;
+module_param(default_utf8, int, S_IRUGO | S_IWUSR);
/*
* ignore_poke: don't unblank the screen when things are typed. This is
@@ -348,10 +351,12 @@ void update_region(struct vc_data *vc, unsigned long start, int count)
/* Structure of attributes is hardware-dependent */
-static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
+static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink,
+ u8 _underline, u8 _reverse, u8 _italic)
{
if (vc->vc_sw->con_build_attr)
- return vc->vc_sw->con_build_attr(vc, _color, _intensity, _blink, _underline, _reverse);
+ return vc->vc_sw->con_build_attr(vc, _color, _intensity,
+ _blink, _underline, _reverse, _italic);
#ifndef VT_BUF_VRAM_ONLY
/*
@@ -368,10 +373,13 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8
u8 a = vc->vc_color;
if (!vc->vc_can_do_color)
return _intensity |
+ (_italic ? 2 : 0) |
(_underline ? 4 : 0) |
(_reverse ? 8 : 0) |
(_blink ? 0x80 : 0);
- if (_underline)
+ if (_italic)
+ a = (a & 0xF0) | vc->vc_itcolor;
+ else if (_underline)
a = (a & 0xf0) | vc->vc_ulcolor;
else if (_intensity == 0)
a = (a & 0xf0) | vc->vc_ulcolor;
@@ -392,8 +400,10 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, u8
static void update_attr(struct vc_data *vc)
{
- vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity, vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm);
- vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm) << 8) | ' ';
+ vc->vc_attr = build_attr(vc, vc->vc_color, vc->vc_intensity,
+ vc->vc_blink, vc->vc_underline,
+ vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
+ vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
}
/* Note: inverting the screen twice should revert to the original state */
@@ -934,6 +944,10 @@ int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+module_param_array(default_red, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_grn, int, NULL, S_IRUGO | S_IWUSR);
+module_param_array(default_blu, int, NULL, S_IRUGO | S_IWUSR);
+
/*
* gotoxy() must verify all boundaries, because the arguments
* might also be negative. If the given position is out of
@@ -1132,6 +1146,7 @@ static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar posi
static void default_attr(struct vc_data *vc)
{
vc->vc_intensity = 1;
+ vc->vc_italic = 0;
vc->vc_underline = 0;
vc->vc_reverse = 0;
vc->vc_blink = 0;
@@ -1154,6 +1169,9 @@ static void csi_m(struct vc_data *vc)
case 2:
vc->vc_intensity = 0;
break;
+ case 3:
+ vc->vc_italic = 1;
+ break;
case 4:
vc->vc_underline = 1;
break;
@@ -1194,6 +1212,9 @@ static void csi_m(struct vc_data *vc)
case 22:
vc->vc_intensity = 1;
break;
+ case 23:
+ vc->vc_italic = 0;
+ break;
case 24:
vc->vc_underline = 0;
break;
@@ -1454,6 +1475,7 @@ static void save_cur(struct vc_data *vc)
vc->vc_saved_x = vc->vc_x;
vc->vc_saved_y = vc->vc_y;
vc->vc_s_intensity = vc->vc_intensity;
+ vc->vc_s_italic = vc->vc_italic;
vc->vc_s_underline = vc->vc_underline;
vc->vc_s_blink = vc->vc_blink;
vc->vc_s_reverse = vc->vc_reverse;
@@ -1468,6 +1490,7 @@ static void restore_cur(struct vc_data *vc)
{
gotoxy(vc, vc->vc_saved_x, vc->vc_saved_y);
vc->vc_intensity = vc->vc_s_intensity;
+ vc->vc_italic = vc->vc_s_italic;
vc->vc_underline = vc->vc_s_underline;
vc->vc_blink = vc->vc_s_blink;
vc->vc_reverse = vc->vc_s_reverse;
@@ -1497,7 +1520,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
vc->vc_charset = 0;
vc->vc_need_wrap = 0;
vc->vc_report_mouse = 0;
- vc->vc_utf = 0;
+ vc->vc_utf = default_utf8;
vc->vc_utf_count = 0;
vc->vc_disp_ctrl = 0;
@@ -1930,7 +1953,47 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
* kernel memory allocation is available.
*/
char con_buf[CON_BUF_SIZE];
-DECLARE_MUTEX(con_buf_sem);
+DEFINE_MUTEX(con_buf_mtx);
+
+/* is_double_width() is based on the wcwidth() implementation by
+ * Markus Kuhn -- 2003-05-20 (Unicode 4.0)
+ * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+ */
+struct interval {
+ uint32_t first;
+ uint32_t last;
+};
+
+static int bisearch(uint32_t ucs, const struct interval *table, int max)
+{
+ int min = 0;
+ int mid;
+
+ if (ucs < table[0].first || ucs > table[max].last)
+ return 0;
+ while (max >= min) {
+ mid = (min + max) / 2;
+ if (ucs > table[mid].last)
+ min = mid + 1;
+ else if (ucs < table[mid].first)
+ max = mid - 1;
+ else
+ return 1;
+ }
+ return 0;
+}
+
+static int is_double_width(uint32_t ucs)
+{
+ static const struct interval double_width[] = {
+ { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
+ { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
+ { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 }, { 0xFFE0, 0xFFE6 },
+ { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
+ };
+ return bisearch(ucs, double_width,
+ sizeof(double_width) / sizeof(*double_width) - 1);
+}
/* acquires console_sem */
static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
@@ -1948,6 +2011,10 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
unsigned int currcons;
unsigned long draw_from = 0, draw_to = 0;
struct vc_data *vc;
+ unsigned char vc_attr;
+ uint8_t rescan;
+ uint8_t inverse;
+ uint8_t width;
u16 himask, charmask;
const unsigned char *orig_buf = NULL;
int orig_count;
@@ -1983,7 +2050,7 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
/* At this point 'buf' is guaranteed to be a kernel buffer
* and therefore no access to userspace (and therefore sleeping)
- * will be needed. The con_buf_sem serializes all tty based
+ * will be needed. The con_buf_mtx serializes all tty based
* console rendering and vcs write/read operations. We hold
* the console spinlock during the entire write.
*/
@@ -2010,53 +2077,86 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
buf++;
n++;
count--;
+ rescan = 0;
+ inverse = 0;
+ width = 1;
/* Do no translation at all in control states */
if (vc->vc_state != ESnormal) {
tc = c;
} else if (vc->vc_utf && !vc->vc_disp_ctrl) {
- /* Combine UTF-8 into Unicode */
- /* Malformed sequences as sequences of replacement glyphs */
+ /* Combine UTF-8 into Unicode in vc_utf_char.
+ * vc_utf_count is the number of continuation bytes still
+ * expected to arrive.
+ * vc_npar is the number of continuation bytes arrived so
+ * far
+ */
rescan_last_byte:
- if(c > 0x7f) {
+ if ((c & 0xc0) == 0x80) {
+ /* Continuation byte received */
+ static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
if (vc->vc_utf_count) {
- if ((c & 0xc0) == 0x80) {
- vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
- if (--vc->vc_utf_count) {
- vc->vc_npar++;
- continue;
- }
- tc = c = vc->vc_utf_char;
- } else
- goto replacement_glyph;
- } else {
- vc->vc_npar = 0;
- if ((c & 0xe0) == 0xc0) {
- vc->vc_utf_count = 1;
- vc->vc_utf_char = (c & 0x1f);
- } else if ((c & 0xf0) == 0xe0) {
- vc->vc_utf_count = 2;
- vc->vc_utf_char = (c & 0x0f);
- } else if ((c & 0xf8) == 0xf0) {
- vc->vc_utf_count = 3;
- vc->vc_utf_char = (c & 0x07);
- } else if ((c & 0xfc) == 0xf8) {
- vc->vc_utf_count = 4;
- vc->vc_utf_char = (c & 0x03);
- } else if ((c & 0xfe) == 0xfc) {
- vc->vc_utf_count = 5;
- vc->vc_utf_char = (c & 0x01);
- } else
- goto replacement_glyph;
+ vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+ vc->vc_npar++;
+ if (--vc->vc_utf_count) {
+ /* Still need some bytes */
continue;
- }
+ }
+ /* Got a whole character */
+ c = vc->vc_utf_char;
+ /* Reject overlong sequences */
+ if (c <= utf8_length_changes[vc->vc_npar - 1] ||
+ c > utf8_length_changes[vc->vc_npar])
+ c = 0xfffd;
+ } else {
+ /* Unexpected continuation byte */
+ vc->vc_utf_count = 0;
+ c = 0xfffd;
+ }
} else {
- if (vc->vc_utf_count)
- goto replacement_glyph;
- tc = c;
+ /* Single ASCII byte or first byte of a sequence received */
+ if (vc->vc_utf_count) {
+ /* Continuation byte expected */
+ rescan = 1;
+ vc->vc_utf_count = 0;
+ c = 0xfffd;
+ } else if (c > 0x7f) {
+ /* First byte of a multibyte sequence received */
+ vc->vc_npar = 0;
+ if ((c & 0xe0) == 0xc0) {
+ vc->vc_utf_count = 1;
+ vc->vc_utf_char = (c & 0x1f);
+ } else if ((c & 0xf0) == 0xe0) {
+ vc->vc_utf_count = 2;
+ vc->vc_utf_char = (c & 0x0f);
+ } else if ((c & 0xf8) == 0xf0) {
+ vc->vc_utf_count = 3;
+ vc->vc_utf_char = (c & 0x07);
+ } else if ((c & 0xfc) == 0xf8) {
+ vc->vc_utf_count = 4;
+ vc->vc_utf_char = (c & 0x03);
+ } else if ((c & 0xfe) == 0xfc) {
+ vc->vc_utf_count = 5;
+ vc->vc_utf_char = (c & 0x01);
+ } else {
+ /* 254 and 255 are invalid */
+ c = 0xfffd;
+ }
+ if (vc->vc_utf_count) {
+ /* Still need some bytes */
+ continue;
+ }
+ }
+ /* Nothing to do if an ASCII byte was received */
}
+ /* End of UTF-8 decoding. */
+ /* c is the received character, or U+FFFD for invalid sequences. */
+ /* Replace invalid Unicode code points with U+FFFD too */
+ if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
+ c = 0xfffd;
+ tc = c;
} else { /* no utf or alternate charset mode */
- tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
+ tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
}
/* If the original code was a control character we
@@ -2076,56 +2176,80 @@ rescan_last_byte:
&& (c != 128+27);
if (vc->vc_state == ESnormal && ok) {
+ if (vc->vc_utf && !vc->vc_disp_ctrl) {
+ if (is_double_width(c))
+ width = 2;
+ }
/* Now try to find out how to display it */
tc = conv_uni_to_pc(vc, tc);
if (tc & ~charmask) {
- if ( tc == -4 ) {
- /* If we got -4 (not found) then see if we have
- defined a replacement character (U+FFFD) */
-replacement_glyph:
- tc = conv_uni_to_pc(vc, 0xfffd);
- if (!(tc & ~charmask))
- goto display_glyph;
- } else if ( tc != -3 )
- continue; /* nothing to display */
- /* no hash table or no replacement --
- * hope for the best */
- if ( c & ~charmask )
- tc = '?';
- else
- tc = c;
+ if (tc == -1 || tc == -2) {
+ continue; /* nothing to display */
+ }
+ /* Glyph not found */
+ if (!(vc->vc_utf && !vc->vc_disp_ctrl) && !(c & ~charmask)) {
+ /* In legacy mode use the glyph we get by a 1:1 mapping.
+ This would make absolutely no sense with Unicode in mind. */
+ tc = c;
+ } else {
+ /* Display U+FFFD. If it's not found, display an inverse question mark. */
+ tc = conv_uni_to_pc(vc, 0xfffd);
+ if (tc < 0) {
+ inverse = 1;
+ tc = conv_uni_to_pc(vc, '?');
+ if (tc < 0) tc = '?';
+ }
+ }
}
-display_glyph:
- if (vc->vc_need_wrap || vc->vc_decim)
- FLUSH
- if (vc->vc_need_wrap) {
- cr(vc);
- lf(vc);
- }
- if (vc->vc_decim)
- insert_char(vc, 1);
- scr_writew(himask ?
- ((vc->vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
- (vc->vc_attr << 8) + tc,
- (u16 *) vc->vc_pos);
- if (DO_UPDATE(vc) && draw_x < 0) {
- draw_x = vc->vc_x;
- draw_from = vc->vc_pos;
- }
- if (vc->vc_x == vc->vc_cols - 1) {
- vc->vc_need_wrap = vc->vc_decawm;
- draw_to = vc->vc_pos + 2;
+ if (!inverse) {
+ vc_attr = vc->vc_attr;
} else {
- vc->vc_x++;
- draw_to = (vc->vc_pos += 2);
+ /* invert vc_attr */
+ if (!vc->vc_can_do_color) {
+ vc_attr = (vc->vc_attr) ^ 0x08;
+ } else if (vc->vc_hi_font_mask == 0x100) {
+ vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
+ } else {
+ vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
+ }
}
- if (vc->vc_utf_count) {
- if (vc->vc_npar) {
- vc->vc_npar--;
- goto display_glyph;
+
+ while (1) {
+ if (vc->vc_need_wrap || vc->vc_decim)
+ FLUSH
+ if (vc->vc_need_wrap) {
+ cr(vc);
+ lf(vc);
+ }
+ if (vc->vc_decim)
+ insert_char(vc, 1);
+ scr_writew(himask ?
+ ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
+ (vc_attr << 8) + tc,
+ (u16 *) vc->vc_pos);
+ if (DO_UPDATE(vc) && draw_x < 0) {
+ draw_x = vc->vc_x;
+ draw_from = vc->vc_pos;
+ }
+ if (vc->vc_x == vc->vc_cols - 1) {
+ vc->vc_need_wrap = vc->vc_decawm;
+ draw_to = vc->vc_pos + 2;
+ } else {
+ vc->vc_x++;
+ draw_to = (vc->vc_pos += 2);
}
- vc->vc_utf_count = 0;
+
+ if (!--width) break;
+
+ tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
+ if (tc < 0) tc = ' ';
+ }
+
+ if (rescan) {
+ rescan = 0;
+ inverse = 0;
+ width = 1;
c = orig;
goto rescan_last_byte;
}
@@ -2581,6 +2705,11 @@ static void con_close(struct tty_struct *tty, struct file *filp)
mutex_unlock(&tty_mutex);
}
+static int default_italic_color = 2; // green (ASCII)
+static int default_underline_color = 3; // cyan (ASCII)
+module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
+module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
+
static void vc_init(struct vc_data *vc, unsigned int rows,
unsigned int cols, int do_clear)
{
@@ -2600,7 +2729,8 @@ static void vc_init(struct vc_data *vc, unsigned int rows,
vc->vc_palette[k++] = default_blu[j] ;
}
vc->vc_def_color = 0x07; /* white */
- vc->vc_ulcolor = 0x0f; /* bold white */
+ vc->vc_ulcolor = default_underline_color;
+ vc->vc_itcolor = default_italic_color;
vc->vc_halfcolor = 0x08; /* grey */
init_waitqueue_head(&vc->paste_wait);
reset_terminal(vc, do_clear);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index c9f2dd620e8..c6f6f420973 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -1061,7 +1061,7 @@ int vt_waitactive(int vt)
schedule();
}
remove_wait_queue(&vt_activate_queue, &wait);
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
return retval;
}
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
index 84074a697dc..b36fa8de213 100644
--- a/drivers/char/watchdog/omap_wdt.c
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -34,7 +34,6 @@
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/reboot.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index 1e4a8d751a7..2f7ba7a514f 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -38,7 +38,6 @@
#include <linux/init.h>
#include <linux/pnp.h>
#include <linux/fs.h>
-#include <linux/pci.h>
#include <asm/semaphore.h>
#include <asm/io.h>
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
index fc0e0347f9d..d4fd0fa2f17 100644
--- a/drivers/char/watchdog/scx200_wdt.c
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -25,7 +25,7 @@
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/fs.h>
-#include <linux/pci.h>
+#include <linux/ioport.h>
#include <linux/scx200.h>
#include <asm/uaccess.h>