summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Config.in4
-rw-r--r--drivers/char/Makefile53
-rw-r--r--drivers/char/acquirewdt.c3
-rw-r--r--drivers/char/adbmouse.c8
-rw-r--r--drivers/char/agp/agp.h16
-rw-r--r--drivers/char/agp/agpgart_be.c359
-rw-r--r--drivers/char/agp/agpgart_fe.c23
-rw-r--r--drivers/char/amigamouse.c8
-rw-r--r--drivers/char/amikeyb.c4
-rw-r--r--drivers/char/amiserial.c8
-rw-r--r--drivers/char/applicom.c1
-rw-r--r--drivers/char/atarimouse.c51
-rw-r--r--drivers/char/atixlmouse.c8
-rw-r--r--drivers/char/bttv.c308
-rw-r--r--drivers/char/bttv.h30
-rw-r--r--drivers/char/busmouse.c28
-rw-r--r--drivers/char/busmouse.h1
-rw-r--r--drivers/char/buz.c1
-rw-r--r--drivers/char/c-qcam.c84
-rw-r--r--drivers/char/console.c3
-rw-r--r--drivers/char/cyclades.c33
-rw-r--r--drivers/char/dn_keyb.c33
-rw-r--r--drivers/char/drm/Makefile14
-rw-r--r--drivers/char/drm/bufs.c4
-rw-r--r--drivers/char/drm/drmP.h6
-rw-r--r--drivers/char/drm/ffb_context.c530
-rw-r--r--drivers/char/drm/ffb_drv.c842
-rw-r--r--drivers/char/drm/ffb_drv.h276
-rw-r--r--drivers/char/drm/fops.c5
-rw-r--r--drivers/char/drm/init.c4
-rw-r--r--drivers/char/drm/proc.c6
-rw-r--r--drivers/char/ds1620.c19
-rw-r--r--drivers/char/dsp56k.c8
-rw-r--r--drivers/char/dtlk.c3
-rw-r--r--drivers/char/efirtc.c1
-rw-r--r--drivers/char/epca.c3
-rw-r--r--drivers/char/generic_serial.c2
-rw-r--r--drivers/char/hp600_keyb.c119
-rw-r--r--drivers/char/i2c-old.c8
-rw-r--r--drivers/char/i810_rng.c885
-rw-r--r--drivers/char/ip2main.c3
-rw-r--r--drivers/char/isicom.c23
-rw-r--r--drivers/char/istallion.c26
-rw-r--r--drivers/char/joystick/joy-amiga.c22
-rw-r--r--drivers/char/joystick/joy-analog.c22
-rw-r--r--drivers/char/joystick/joy-assassin.c28
-rw-r--r--drivers/char/joystick/joy-console.c3
-rw-r--r--drivers/char/joystick/joy-creative.c22
-rw-r--r--drivers/char/joystick/joy-db9.c3
-rw-r--r--drivers/char/joystick/joy-gravis.c22
-rw-r--r--drivers/char/joystick/joy-lightning.c22
-rw-r--r--drivers/char/joystick/joy-logitech.c22
-rw-r--r--drivers/char/joystick/joy-magellan.c4
-rw-r--r--drivers/char/joystick/joy-pci.c25
-rw-r--r--drivers/char/joystick/joy-sidewinder.c22
-rw-r--r--drivers/char/joystick/joy-spaceball.c4
-rw-r--r--drivers/char/joystick/joy-spaceorb.c4
-rw-r--r--drivers/char/joystick/joy-thrustmaster.c22
-rw-r--r--drivers/char/joystick/joy-turbografx.c3
-rw-r--r--drivers/char/joystick/joy-warrior.c4
-rw-r--r--drivers/char/joystick/joystick.c30
-rw-r--r--drivers/char/logibusmouse.c4
-rw-r--r--drivers/char/lp.c8
-rw-r--r--drivers/char/misc.c13
-rw-r--r--drivers/char/mixcomwd.c4
-rw-r--r--drivers/char/msbusmouse.c4
-rw-r--r--drivers/char/msp3400.c33
-rw-r--r--drivers/char/mxser.c2
-rw-r--r--drivers/char/n_hdlc.c2
-rw-r--r--drivers/char/n_tty.c6
-rw-r--r--drivers/char/nvram.c3
-rw-r--r--drivers/char/nwbutton.c31
-rw-r--r--drivers/char/nwflash.c12
-rw-r--r--drivers/char/pc110pad.c6
-rw-r--r--drivers/char/pc_keyb.c7
-rw-r--r--drivers/char/pcmcia/serial_cb.c1
-rw-r--r--drivers/char/pcwd.c3
-rw-r--r--drivers/char/ppdev.c90
-rw-r--r--drivers/char/qpmouse.c6
-rw-r--r--drivers/char/radio-aimslab.c2
-rw-r--r--drivers/char/random.c2
-rw-r--r--drivers/char/rio/rio_linux.c33
-rw-r--r--drivers/char/rocket.c5
-rw-r--r--drivers/char/rtc.c10
-rw-r--r--drivers/char/sbc60xxwdt.c338
-rw-r--r--drivers/char/scan_keyb.c129
-rw-r--r--drivers/char/scan_keyb.h15
-rw-r--r--drivers/char/serial.c833
-rw-r--r--drivers/char/sh-sci.c500
-rw-r--r--drivers/char/sh-sci.h441
-rw-r--r--drivers/char/stallion.c48
-rw-r--r--drivers/char/stradis.c9
-rw-r--r--drivers/char/sx.c24
-rw-r--r--drivers/char/tpqic02.c8
-rw-r--r--drivers/char/tty_io.c43
-rw-r--r--drivers/char/tuner.c14
-rw-r--r--drivers/char/tvmixer.c351
-rw-r--r--drivers/char/videodev.c16
-rw-r--r--drivers/char/vt.c6
-rw-r--r--drivers/char/wdt.c4
-rw-r--r--drivers/char/wdt_pci.c133
101 files changed, 5805 insertions, 1532 deletions
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 5fed698d6..f18158004 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -124,6 +124,7 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
tristate ' Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
+ tristate ' SBC-60XX Watchdog Timer' CONFIG_60XX_WDT
tristate ' Mixcom Watchdog' CONFIG_MIXCOMWD
if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then
tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG
@@ -143,6 +144,7 @@ if [ "$CONFIG_ARCH_NETWINDER" = "y" ]; then
tristate 'NetWinder flash support' CONFIG_NWFLASH
fi
+dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI
tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'Enhanced Real Time Clock Support' CONFIG_RTC
if [ "$CONFIG_IA64" = "y" ]; then
@@ -206,7 +208,7 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
fi
comment 'Video Adapters'
if [ "$CONFIG_I2C_ALGOBIT" = "y" -o "$CONFIG_I2C_ALGOBIT" = "m" ]; then
- dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT $CONFIG_SOUND
+ dep_tristate ' BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV $CONFIG_PCI $CONFIG_I2C_ALGOBIT
fi
dep_tristate ' Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
if [ "$CONFIG_ALL_PPC" = "y" ]; then
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index f75dabd18..cf145729a 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -56,7 +56,7 @@ ifeq ($(ARCH),m68k)
ifdef CONFIG_AMIGA
KEYBD = amikeyb.o
else
- KEYBD =
+ KEYBD =
endif
SERIAL =
endif
@@ -65,7 +65,6 @@ ifeq ($(ARCH),arm)
KEYMAP =
KEYBD =
CONSOLE =
- SERIAL =
endif
ifeq ($(ARCH),sh)
@@ -73,6 +72,11 @@ ifeq ($(ARCH),sh)
KEYBD =
CONSOLE =
SERIAL =
+ ifeq ($(CONFIG_SH_HP600),y)
+ KEYMAP = defkeymap.o
+ KEYBD = scan_keyb.o hp600_keyb.o
+ CONSOLE = console.o
+ endif
ifeq ($(CONFIG_SERIAL),y)
SERIAL = generic_serial.o sh-sci.o
else
@@ -134,40 +138,22 @@ obj-$(CONFIG_SYNCLINK) += synclink.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_SPECIALIX) += specialix.o
obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
-obj-$(CONFIG_SX) += sx.o
-
-# If either SX or RIO is in the kernel, generic_serial goes in the
-# kernel, and the module is no longer required. The "in kernel" case
-# is last to be able to override the module case.... This is an
-# example of the new "makefile automatically figures out the
-# dependencies".... -- REW
-
-GS=n
-ifeq ($(CONFIG_RIO),m)
- M_OBJS += generic_serial.o
- MOD_SUB_DIRS += rio
- GS = m
-endif
-ifeq ($(CONFIG_SX),m)
- GS = m
- M_OBJS += sx.o
-endif
+# After much ado, we found that an object can safely be declared as
+# both a module and into the kernel. Below that is filtered out.
+# So this should simply provide the wanted functionality!
+obj-$(CONFIG_SX) += sx.o generic_serial.o
+obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o
+
ifeq ($(CONFIG_RIO),y)
- L_OBJS += rio/rio.o generic_serial.o
SUB_DIRS += rio
- MOD_SUB_DIRS += rio
- GS = y
-endif
-
-ifeq ($(CONFIG_SX),y)
- L_OBJS += sx.o
- GS = y
+else
+ ifeq ($(CONFIG_RIO),m)
+ MOD_SUB_DIRS += rio
+ endif
endif
-obj-$(GS) += generic_serial.o
-
obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
obj-$(CONFIG_PRINTER) += lp.o
@@ -200,6 +186,7 @@ obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
obj-$(CONFIG_PCWATCHDOG) += pcwd.o
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
+obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
obj-$(CONFIG_AMIGAMOUSE) += amigamouse.o
obj-$(CONFIG_ATARIMOUSE) += atarimouse.o
obj-$(CONFIG_ADBMOUSE) += adbmouse.o
@@ -217,6 +204,7 @@ obj-$(CONFIG_VIDEO_DEV) += videodev.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_DS1620) += ds1620.o
+obj-$(CONFIG_INTEL_RNG) += i810_rng.o
#
# for external dependencies in arm/config.in and video/config.in
@@ -238,6 +226,7 @@ else
L_TUNERS=m
endif
endif
+obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
ifeq ($(CONFIG_VIDEO_ZR36120),y)
@@ -336,10 +325,6 @@ endif
obj-$(CONFIG_NWBUTTON) += nwbutton.o
obj-$(CONFIG_NWFLASH) += nwflash.o
-ifeq ($(CONFIG_DZ),y)
- L_OBJS += dz.o
-endif
-
ifeq ($(CONFIG_DRM),y)
SUB_DIRS += drm
ALL_SUB_DIRS += drm
diff --git a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
index 9d86479dc..eaa9e6bae 100644
--- a/drivers/char/acquirewdt.c
+++ b/drivers/char/acquirewdt.c
@@ -125,7 +125,6 @@ static int acq_open(struct inode *inode, struct file *file)
spin_unlock(&acq_lock);
return -EBUSY;
}
- MOD_INC_USE_COUNT;
/*
* Activate
*/
@@ -150,7 +149,6 @@ static int acq_close(struct inode *inode, struct file *file)
acq_is_open=0;
spin_unlock(&acq_lock);
}
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -175,6 +173,7 @@ static int acq_notify_sys(struct notifier_block *this, unsigned long code,
static struct file_operations acq_fops = {
+ owner: THIS_MODULE,
read: acq_read,
write: acq_write,
ioctl: acq_ioctl,
diff --git a/drivers/char/adbmouse.c b/drivers/char/adbmouse.c
index a33693c14..a4108cf0e 100644
--- a/drivers/char/adbmouse.c
+++ b/drivers/char/adbmouse.c
@@ -132,20 +132,22 @@ static void adb_mouse_interrupt(unsigned char *buf, int nb)
static int release_mouse(struct inode *inode, struct file *file)
{
adb_mouse_interrupt_hook = NULL;
- MOD_DEC_USE_COUNT;
+ /*
+ * FIXME?: adb_mouse_interrupt_hook may still be executing
+ * on another CPU.
+ */
return 0;
}
static int open_mouse(struct inode *inode, struct file *file)
{
- MOD_INC_USE_COUNT;
adb_mouse_interrupt_hook = adb_mouse_interrupt;
return 0;
}
static struct busmouse adb_mouse =
{
- ADB_MOUSE_MINOR, "adbmouse", open_mouse, release_mouse, 7
+ ADB_MOUSE_MINOR, "adbmouse", THIS_MODULE, open_mouse, release_mouse, 7
};
static int __init adb_mouse_init(void)
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 21a638fe2..355a9a8d1 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -31,6 +31,7 @@ enum aper_size_type {
U8_APER_SIZE,
U16_APER_SIZE,
U32_APER_SIZE,
+ LVL2_APER_SIZE,
FIXED_APER_SIZE
};
@@ -63,6 +64,12 @@ typedef struct _aper_size_info_32 {
u32 size_value;
} aper_size_info_32;
+typedef struct _aper_size_info_lvl2 {
+ int size;
+ int num_entries;
+ u32 size_value;
+} aper_size_info_lvl2;
+
typedef struct _aper_size_info_fixed {
int size;
int num_entries;
@@ -124,10 +131,12 @@ struct agp_bridge_data {
#define A_SIZE_8(x) ((aper_size_info_8 *) x)
#define A_SIZE_16(x) ((aper_size_info_16 *) x)
#define A_SIZE_32(x) ((aper_size_info_32 *) x)
+#define A_SIZE_LVL2(x) ((aper_size_info_lvl2 *) x)
#define A_SIZE_FIX(x) ((aper_size_info_fixed *) x)
#define A_IDX8() (A_SIZE_8(agp_bridge.aperture_sizes) + i)
#define A_IDX16() (A_SIZE_16(agp_bridge.aperture_sizes) + i)
#define A_IDX32() (A_SIZE_32(agp_bridge.aperture_sizes) + i)
+#define A_IDXLVL2() (A_SIZE_LVL2(agp_bridge.aperture_sizes) + i)
#define A_IDXFIX() (A_SIZE_FIX(agp_bridge.aperture_sizes) + i)
#define MAXKEY (4096 * 32)
@@ -151,6 +160,9 @@ struct agp_bridge_data {
#ifndef PCI_DEVICE_ID_INTEL_810_0
#define PCI_DEVICE_ID_INTEL_810_0 0x7120
#endif
+#ifndef PCI_DEVICE_ID_INTEL_840_0
+#define PCI_DEVICE_ID_INTEL_840_0 0x1a21
+#endif
#ifndef PCI_DEVICE_ID_INTEL_810_DC100_0
#define PCI_DEVICE_ID_INTEL_810_DC100_0 0x7122
#endif
@@ -190,6 +202,10 @@ struct agp_bridge_data {
#define INTEL_NBXCFG 0x50
#define INTEL_ERRSTS 0x91
+/* intel i840 registers */
+#define INTEL_I840_MCHCFG 0x50
+#define INTEL_I840_ERRSTS 0xc8
+
/* intel i810 registers */
#define I810_GMADDR 0x10
#define I810_MMADDR 0x14
diff --git a/drivers/char/agp/agpgart_be.c b/drivers/char/agp/agpgart_be.c
index 274c9a86b..dcc8176f9 100644
--- a/drivers/char/agp/agpgart_be.c
+++ b/drivers/char/agp/agpgart_be.c
@@ -315,6 +315,9 @@ static int agp_return_size(void)
case U32_APER_SIZE:
current_size = A_SIZE_32(temp)->size;
break;
+ case LVL2_APER_SIZE:
+ current_size = A_SIZE_LVL2(temp)->size;
+ break;
case FIXED_APER_SIZE:
current_size = A_SIZE_FIX(temp)->size;
break;
@@ -539,6 +542,11 @@ static int agp_generic_create_gatt_table(void)
int i;
void *temp;
+ /* The generic routines can't handle 2 level gatt's */
+ if (agp_bridge.size_type == LVL2_APER_SIZE) {
+ return -EINVAL;
+ }
+
table = NULL;
i = agp_bridge.aperture_size_idx;
temp = agp_bridge.current_size;
@@ -566,6 +574,7 @@ static int agp_generic_create_gatt_table(void)
break;
/* This case will never really happen. */
case FIXED_APER_SIZE:
+ case LVL2_APER_SIZE:
default:
size = page_order = num_entries = 0;
break;
@@ -590,6 +599,7 @@ static int agp_generic_create_gatt_table(void)
* happen.
*/
case FIXED_APER_SIZE:
+ case LVL2_APER_SIZE:
default:
agp_bridge.current_size =
agp_bridge.current_size;
@@ -663,6 +673,10 @@ static int agp_generic_free_gatt_table(void)
case FIXED_APER_SIZE:
page_order = A_SIZE_FIX(temp)->page_order;
break;
+ case LVL2_APER_SIZE:
+ /* The generic routines can't deal with 2 level gatt's */
+ return -EINVAL;
+ break;
default:
page_order = 0;
break;
@@ -706,6 +720,10 @@ static int agp_generic_insert_memory(agp_memory * mem,
case FIXED_APER_SIZE:
num_entries = A_SIZE_FIX(temp)->num_entries;
break;
+ case LVL2_APER_SIZE:
+ /* The generic routines can't deal with 2 level gatt's */
+ return -EINVAL;
+ break;
default:
num_entries = 0;
break;
@@ -1126,6 +1144,38 @@ static int intel_configure(void)
return 0;
}
+static int intel_840_configure(void)
+{
+ u32 temp;
+ u16 temp2;
+ aper_size_info_16 *current_size;
+
+ current_size = A_SIZE_16(agp_bridge.current_size);
+
+ /* aperture size */
+ pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE,
+ (char)current_size->size_value);
+
+ /* address to map to */
+ pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
+ agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+
+ /* attbase - aperture base */
+ pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE,
+ agp_bridge.gatt_bus_addr);
+
+ /* agpctrl */
+ pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
+
+ /* mcgcfg */
+ pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2);
+ pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG,
+ temp2 | (1 << 9));
+ /* clear any possible error conditions */
+ pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000);
+ return 0;
+}
+
static unsigned long intel_mask_memory(unsigned long addr, int type)
{
/* Memory type is ignored */
@@ -1179,6 +1229,34 @@ static int __init intel_generic_setup (struct pci_dev *pdev)
(void) pdev; /* unused */
}
+static int __init intel_840_setup (struct pci_dev *pdev)
+{
+ agp_bridge.masks = intel_generic_masks;
+ agp_bridge.num_of_masks = 1;
+ agp_bridge.aperture_sizes = (void *) intel_generic_sizes;
+ agp_bridge.size_type = U16_APER_SIZE;
+ agp_bridge.num_aperture_sizes = 7;
+ agp_bridge.dev_private_data = NULL;
+ agp_bridge.needs_scratch_page = FALSE;
+ agp_bridge.configure = intel_840_configure;
+ agp_bridge.fetch_size = intel_fetch_size;
+ agp_bridge.cleanup = intel_cleanup;
+ agp_bridge.tlb_flush = intel_tlbflush;
+ agp_bridge.mask_memory = intel_mask_memory;
+ agp_bridge.agp_enable = agp_generic_agp_enable;
+ agp_bridge.cache_flush = global_cache_flush;
+ agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
+ agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
+ agp_bridge.insert_memory = agp_generic_insert_memory;
+ agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+ agp_bridge.free_by_type = agp_generic_free_by_type;
+
+ return 0;
+
+ (void) pdev; /* unused */
+}
+
#endif /* CONFIG_AGP_INTEL */
#ifdef CONFIG_AGP_VIA
@@ -1403,19 +1481,180 @@ static int __init sis_generic_setup (struct pci_dev *pdev)
#ifdef CONFIG_AGP_AMD
+typedef struct _amd_page_map {
+ unsigned long *real;
+ unsigned long *remapped;
+} amd_page_map;
+
static struct _amd_irongate_private {
volatile u8 *registers;
+ amd_page_map **gatt_pages;
+ int num_tables;
} amd_irongate_private;
+static int amd_create_page_map(amd_page_map *page_map)
+{
+ int i;
+
+ page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
+ if (page_map->real == NULL) {
+ return -ENOMEM;
+ }
+ set_bit(PG_reserved, &mem_map[MAP_NR(page_map->real)].flags);
+ CACHE_FLUSH();
+ page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real),
+ PAGE_SIZE);
+ if (page_map->remapped == NULL) {
+ clear_bit(PG_reserved,
+ &mem_map[MAP_NR(page_map->real)].flags);
+ free_page((unsigned long) page_map->real);
+ page_map->real = NULL;
+ return -ENOMEM;
+ }
+ CACHE_FLUSH();
+
+ for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
+ page_map->remapped[i] = agp_bridge.scratch_page;
+ }
+
+ return 0;
+}
+
+static void amd_free_page_map(amd_page_map *page_map)
+{
+ iounmap(page_map->remapped);
+ clear_bit(PG_reserved,
+ &mem_map[MAP_NR(page_map->real)].flags);
+ free_page((unsigned long) page_map->real);
+}
+
+static void amd_free_gatt_pages(void)
+{
+ int i;
+ amd_page_map **tables;
+ amd_page_map *entry;
+
+ tables = amd_irongate_private.gatt_pages;
+ for(i = 0; i < amd_irongate_private.num_tables; i++) {
+ entry = tables[i];
+ if (entry != NULL) {
+ if (entry->real != NULL) {
+ amd_free_page_map(entry);
+ }
+ kfree(entry);
+ }
+ }
+ kfree(tables);
+}
+
+static int amd_create_gatt_pages(int nr_tables)
+{
+ amd_page_map **tables;
+ amd_page_map *entry;
+ int retval = 0;
+ int i;
+
+ tables = kmalloc((nr_tables + 1) * sizeof(amd_page_map *),
+ GFP_KERNEL);
+ if (tables == NULL) {
+ return -ENOMEM;
+ }
+ memset(tables, 0, sizeof(amd_page_map *) * (nr_tables + 1));
+ for (i = 0; i < nr_tables; i++) {
+ entry = kmalloc(sizeof(amd_page_map), GFP_KERNEL);
+ if (entry == NULL) {
+ retval = -ENOMEM;
+ break;
+ }
+ memset(entry, 0, sizeof(amd_page_map));
+ tables[i] = entry;
+ retval = amd_create_page_map(entry);
+ if (retval != 0) break;
+ }
+ amd_irongate_private.num_tables = nr_tables;
+ amd_irongate_private.gatt_pages = tables;
+
+ if (retval != 0) amd_free_gatt_pages();
+
+ return retval;
+}
+
+/* Since we don't need contigious memory we just try
+ * to get the gatt table once
+ */
+
+#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
+#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
+ GET_PAGE_DIR_OFF(agp_bridge.gart_bus_addr))
+#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
+#define GET_GATT(addr) (amd_irongate_private.gatt_pages[\
+ GET_PAGE_DIR_IDX(addr)]->remapped)
+
+static int amd_create_gatt_table(void)
+{
+ aper_size_info_lvl2 *value;
+ amd_page_map page_dir;
+ unsigned long addr;
+ int retval;
+ u32 temp;
+ int i;
+
+ value = A_SIZE_LVL2(agp_bridge.current_size);
+ retval = amd_create_page_map(&page_dir);
+ if (retval != 0) {
+ return retval;
+ }
+
+ retval = amd_create_gatt_pages(value->num_entries / 1024);
+ if (retval != 0) {
+ amd_free_page_map(&page_dir);
+ return retval;
+ }
+
+ agp_bridge.gatt_table_real = page_dir.real;
+ agp_bridge.gatt_table = page_dir.remapped;
+ agp_bridge.gatt_bus_addr = virt_to_bus(page_dir.real);
+
+ /* Get the address for the gart region.
+ * This is a bus address even on the alpha, b/c its
+ * used to program the agp master not the cpu
+ */
+
+ pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp);
+ addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
+ agp_bridge.gart_bus_addr = addr;
+
+ /* Calculate the agp offset */
+ for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
+ page_dir.remapped[GET_PAGE_DIR_OFF(addr)] =
+ virt_to_bus(amd_irongate_private.gatt_pages[i]->real);
+ page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001;
+ }
+
+ return 0;
+}
+
+static int amd_free_gatt_table(void)
+{
+ amd_page_map page_dir;
+
+ page_dir.real = agp_bridge.gatt_table_real;
+ page_dir.remapped = agp_bridge.gatt_table;
+
+ amd_free_gatt_pages();
+ amd_free_page_map(&page_dir);
+ return 0;
+}
+
static int amd_irongate_fetch_size(void)
{
int i;
u32 temp;
- aper_size_info_32 *values;
+ aper_size_info_lvl2 *values;
pci_read_config_dword(agp_bridge.dev, AMD_APSIZE, &temp);
temp = (temp & 0x0000000e);
- values = A_SIZE_32(agp_bridge.aperture_sizes);
+ values = A_SIZE_LVL2(agp_bridge.aperture_sizes);
for (i = 0; i < agp_bridge.num_aperture_sizes; i++) {
if (temp == values[i].size_value) {
agp_bridge.previous_size =
@@ -1431,12 +1670,11 @@ static int amd_irongate_fetch_size(void)
static int amd_irongate_configure(void)
{
- aper_size_info_32 *current_size;
- unsigned long addr;
+ aper_size_info_lvl2 *current_size;
u32 temp;
u16 enable_reg;
- current_size = A_SIZE_32(agp_bridge.current_size);
+ current_size = A_SIZE_LVL2(agp_bridge.current_size);
/* Get the memory mapped registers */
pci_read_config_dword(agp_bridge.dev, AMD_MMBASE, &temp);
@@ -1451,7 +1689,7 @@ static int amd_irongate_configure(void)
pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL, 0x80);
/* Set indexing mode */
- pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x02);
+ pci_write_config_byte(agp_bridge.dev, AMD_MODECNTL2, 0x00);
/* Write the enable register */
enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE);
@@ -1467,28 +1705,16 @@ static int amd_irongate_configure(void)
/* Flush the tlb */
OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001);
- /* Get the address for the gart region */
- pci_read_config_dword(agp_bridge.dev, AMD_APBASE, &temp);
- addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
-#ifdef __alpha__
- /* ??? Presumably what is wanted is the bus address as seen
- from the CPU side, since it appears that this value is
- exported to userland via an ioctl. The terminology below
- is confused, mixing `physical address' with `bus address',
- as x86 folk are wont to do. */
- addr = virt_to_phys(ioremap(addr, 0));
-#endif
- agp_bridge.gart_bus_addr = addr;
return 0;
}
static void amd_irongate_cleanup(void)
{
- aper_size_info_32 *previous_size;
+ aper_size_info_lvl2 *previous_size;
u32 temp;
u16 enable_reg;
- previous_size = A_SIZE_32(agp_bridge.previous_size);
+ previous_size = A_SIZE_LVL2(agp_bridge.previous_size);
enable_reg = INREG16(amd_irongate_private.registers, AMD_GARTENABLE);
enable_reg = (enable_reg & ~(0x0004));
@@ -1521,15 +1747,76 @@ static unsigned long amd_irongate_mask_memory(unsigned long addr, int type)
return addr | agp_bridge.masks[0].mask;
}
-static aper_size_info_32 amd_irongate_sizes[7] =
+static int amd_insert_memory(agp_memory * mem,
+ off_t pg_start, int type)
{
- {2048, 524288, 9, 0x0000000c},
- {1024, 262144, 8, 0x0000000a},
- {512, 131072, 7, 0x00000008},
- {256, 65536, 6, 0x00000006},
- {128, 32768, 5, 0x00000004},
- {64, 16384, 4, 0x00000002},
- {32, 8192, 3, 0x00000000}
+ int i, j, num_entries;
+ unsigned long *cur_gatt;
+ unsigned long addr;
+
+ num_entries = A_SIZE_LVL2(agp_bridge.current_size)->num_entries;
+
+ if (type != 0 || mem->type != 0) {
+ return -EINVAL;
+ }
+ if ((pg_start + mem->page_count) > num_entries) {
+ return -EINVAL;
+ }
+
+ j = pg_start;
+ while (j < (pg_start + mem->page_count)) {
+ addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+ cur_gatt = GET_GATT(addr);
+ if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) {
+ return -EBUSY;
+ }
+ j++;
+ }
+
+ if (mem->is_flushed == FALSE) {
+ CACHE_FLUSH();
+ mem->is_flushed = TRUE;
+ }
+
+ for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+ addr = (j * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+ cur_gatt = GET_GATT(addr);
+ cur_gatt[GET_GATT_OFF(addr)] = mem->memory[i];
+ }
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+static int amd_remove_memory(agp_memory * mem, off_t pg_start,
+ int type)
+{
+ int i;
+ unsigned long *cur_gatt;
+ unsigned long addr;
+
+ if (type != 0 || mem->type != 0) {
+ return -EINVAL;
+ }
+ for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+ addr = (i * PAGE_SIZE) + agp_bridge.gart_bus_addr;
+ cur_gatt = GET_GATT(addr);
+ cur_gatt[GET_GATT_OFF(addr)] =
+ (unsigned long) agp_bridge.scratch_page;
+ }
+
+ agp_bridge.tlb_flush(mem);
+ return 0;
+}
+
+static aper_size_info_lvl2 amd_irongate_sizes[7] =
+{
+ {2048, 524288, 0x0000000c},
+ {1024, 262144, 0x0000000a},
+ {512, 131072, 0x00000008},
+ {256, 65536, 0x00000006},
+ {128, 32768, 0x00000004},
+ {64, 16384, 0x00000002},
+ {32, 8192, 0x00000000}
};
static gatt_mask amd_irongate_masks[] =
@@ -1542,7 +1829,7 @@ static int __init amd_irongate_setup (struct pci_dev *pdev)
agp_bridge.masks = amd_irongate_masks;
agp_bridge.num_of_masks = 1;
agp_bridge.aperture_sizes = (void *) amd_irongate_sizes;
- agp_bridge.size_type = U32_APER_SIZE;
+ agp_bridge.size_type = LVL2_APER_SIZE;
agp_bridge.num_aperture_sizes = 7;
agp_bridge.dev_private_data = (void *) &amd_irongate_private;
agp_bridge.needs_scratch_page = FALSE;
@@ -1553,10 +1840,10 @@ static int __init amd_irongate_setup (struct pci_dev *pdev)
agp_bridge.mask_memory = amd_irongate_mask_memory;
agp_bridge.agp_enable = agp_generic_agp_enable;
agp_bridge.cache_flush = global_cache_flush;
- agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
- agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
- agp_bridge.insert_memory = agp_generic_insert_memory;
- agp_bridge.remove_memory = agp_generic_remove_memory;
+ agp_bridge.create_gatt_table = amd_create_gatt_table;
+ agp_bridge.free_gatt_table = amd_free_gatt_table;
+ agp_bridge.insert_memory = amd_insert_memory;
+ agp_bridge.remove_memory = amd_remove_memory;
agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
agp_bridge.free_by_type = agp_generic_free_by_type;
@@ -1755,6 +2042,12 @@ static struct {
"Intel",
"440GX",
intel_generic_setup },
+ { PCI_DEVICE_ID_INTEL_840_0,
+ PCI_VENDOR_ID_INTEL,
+ INTEL_I840,
+ "Intel",
+ "i840",
+ intel_840_setup },
{ 0,
PCI_VENDOR_ID_INTEL,
INTEL_GENERIC,
diff --git a/drivers/char/agp/agpgart_fe.c b/drivers/char/agp/agpgart_fe.c
index 199d5c079..e67beef38 100644
--- a/drivers/char/agp/agpgart_fe.c
+++ b/drivers/char/agp/agpgart_fe.c
@@ -687,7 +687,6 @@ static int agp_release(struct inode *inode, struct file *file)
}
agp_remove_file_private(priv);
kfree(priv);
- MOD_DEC_USE_COUNT;
AGP_UNLOCK();
return 0;
}
@@ -697,19 +696,17 @@ static int agp_open(struct inode *inode, struct file *file)
int minor = MINOR(inode->i_rdev);
agp_file_private *priv;
agp_client *client;
+ int rc = -ENXIO;
AGP_LOCK();
- if (minor != AGPGART_MINOR) {
- AGP_UNLOCK();
- return -ENXIO;
- }
+ if (minor != AGPGART_MINOR)
+ goto err_out;
+
priv = kmalloc(sizeof(agp_file_private), GFP_KERNEL);
+ if (priv == NULL)
+ goto err_out_nomem;
- if (priv == NULL) {
- AGP_UNLOCK();
- return -ENOMEM;
- }
memset(priv, 0, sizeof(agp_file_private));
set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags);
priv->my_pid = current->pid;
@@ -726,9 +723,14 @@ static int agp_open(struct inode *inode, struct file *file)
}
file->private_data = (void *) priv;
agp_insert_file_private(priv);
- MOD_INC_USE_COUNT;
AGP_UNLOCK();
return 0;
+
+err_out_nomem:
+ rc = -ENOMEM;
+err_out:
+ AGP_UNLOCK();
+ return rc;
}
@@ -1059,6 +1061,7 @@ ioctl_out:
static struct file_operations agp_fops =
{
+ owner: THIS_MODULE,
llseek: agp_lseek,
read: agp_read,
write: agp_write,
diff --git a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c
index 0cdfc264a..b7b6c3cc2 100644
--- a/drivers/char/amigamouse.c
+++ b/drivers/char/amigamouse.c
@@ -151,7 +151,6 @@ static int release_mouse(struct inode * inode, struct file * file)
#if AMIGA_OLD_INT
AMI_MSE_INT_OFF();
#endif
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -162,10 +161,6 @@ static int release_mouse(struct inode * inode, struct file * file)
static int open_mouse(struct inode * inode, struct file * file)
{
- /* Lock module first - request_irq might sleep */
-
- MOD_INC_USE_COUNT;
-
/*
* use VBL to poll mouse deltas
*/
@@ -173,7 +168,6 @@ static int open_mouse(struct inode * inode, struct file * file)
if(request_irq(IRQ_AMIGA_VERTB, mouse_interrupt, 0,
"Amiga mouse", mouse_interrupt)) {
printk(KERN_INFO "Installing Amiga mouse failed.\n");
- MOD_DEC_USE_COUNT;
return -EIO;
}
@@ -184,7 +178,7 @@ static int open_mouse(struct inode * inode, struct file * file)
}
static struct busmouse amigamouse = {
- AMIGAMOUSE_MINOR, "amigamouse", open_mouse, release_mouse, 7
+ AMIGAMOUSE_MINOR, "amigamouse", THIS_MODULE, open_mouse, release_mouse, 7
};
static int __init amiga_mouse_init(void)
diff --git a/drivers/char/amikeyb.c b/drivers/char/amikeyb.c
index 41bb7ac15..15e21be68 100644
--- a/drivers/char/amikeyb.c
+++ b/drivers/char/amikeyb.c
@@ -186,8 +186,8 @@ static void amikeyb_rep(unsigned long ignore)
kbd_pt_regs = NULL;
+ init_timer(&amikeyb_rep_timer);
amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
- amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
add_timer(&amikeyb_rep_timer);
handle_scancode(rep_scancode, 1);
@@ -254,8 +254,8 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp)
} else {
del_timer(&amikeyb_rep_timer);
rep_scancode = keycode;
+ init_timer(&amikeyb_rep_timer);
amikeyb_rep_timer.expires = jiffies + key_repeat_delay;
- amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
add_timer(&amikeyb_rep_timer);
}
handle_scancode(keycode, !break_flag);
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index b41ec9229..29614cfd9 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -2104,6 +2104,13 @@ int __init rs_init(void)
if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL))
return -ENODEV;
+ /*
+ * We request SERDAT and SERPER only, because the serial registers are
+ * too spreaded over the custom register space
+ */
+ if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4, "amiserial [Paula]"))
+ return -EBUSY;
+
init_bh(SERIAL_BH, do_serial_bh);
IRQ_ports = NULL;
@@ -2254,6 +2261,7 @@ void cleanup_module(void)
free_page((unsigned long) tmp_buf);
tmp_buf = NULL;
}
+ release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
}
#endif /* MODULE */
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index d5091ff4d..3fc7005ed 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -226,6 +226,7 @@ int __init applicom_init(void)
continue;
}
+ /* &ac_open as dev_id? David, could you pass me this joint? */
if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open)) {
printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
iounmap(RamIO);
diff --git a/drivers/char/atarimouse.c b/drivers/char/atarimouse.c
index a188320c2..ce0843725 100644
--- a/drivers/char/atarimouse.c
+++ b/drivers/char/atarimouse.c
@@ -39,53 +39,50 @@ extern int atari_mouse_buttons;
static void atari_mouse_interrupt(char *buf)
{
- int buttons;
+ int buttons;
-/* ikbd_mouse_disable(); */
+/* ikbd_mouse_disable(); */
- buttons = ((buf[0] & 1)
+ buttons = ((buf[0] & 1)
| ((buf[0] & 2) << 1)
| (atari_mouse_buttons & 2));
- atari_mouse_buttons = buttons;
+ atari_mouse_buttons = buttons;
- busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons ^ 7);
-/* ikbd_mouse_rel_pos(); */
+ busmouse_add_movementbuttons(msedev, buf[1], -buf[2], buttons ^ 7);
+/* ikbd_mouse_rel_pos(); */
}
static int release_mouse(struct inode *inode, struct file *file)
{
- ikbd_mouse_disable();
-
- atari_mouse_interrupt_hook = NULL;
- MOD_DEC_USE_COUNT;
- return 0;
+ ikbd_mouse_disable();
+ atari_mouse_interrupt_hook = NULL;
+ return 0;
}
static int open_mouse(struct inode *inode, struct file *file)
{
- atari_mouse_buttons = 0;
- ikbd_mouse_y0_top ();
- ikbd_mouse_thresh (mouse_threshold[0], mouse_threshold[1]);
- ikbd_mouse_rel_pos();
- MOD_INC_USE_COUNT;
- atari_mouse_interrupt_hook = atari_mouse_interrupt;
- return 0;
+ atari_mouse_buttons = 0;
+ ikbd_mouse_y0_top ();
+ ikbd_mouse_thresh (mouse_threshold[0], mouse_threshold[1]);
+ ikbd_mouse_rel_pos();
+ atari_mouse_interrupt_hook = atari_mouse_interrupt;
+ return 0;
}
static struct busmouse atarimouse = {
- ATARIMOUSE_MINOR, "atarimouse", open_mouse, release_mouse, 0
+ ATARIMOUSE_MINOR, "atarimouse", THIS_MODULE, open_mouse, release_mouse, 0
};
static int __init atari_mouse_init(void)
{
- if (!MACH_IS_ATARI)
- return -ENODEV;
- msedev = register_busmouse(&atarimouse);
- if (msedev < 0)
- printk(KERN_WARNING "Unable to register Atari mouse driver.\n");
- else
- printk(KERN_INFO "Atari mouse installed.\n");
- return msedev < 0 ? msedev : 0;
+ if (!MACH_IS_ATARI)
+ return -ENODEV;
+ msedev = register_busmouse(&atarimouse);
+ if (msedev < 0)
+ printk(KERN_WARNING "Unable to register Atari mouse driver.\n");
+ else
+ printk(KERN_INFO "Atari mouse installed.\n");
+ return msedev < 0 ? msedev : 0;
}
diff --git a/drivers/char/atixlmouse.c b/drivers/char/atixlmouse.c
index 223793374..e515d0fa5 100644
--- a/drivers/char/atixlmouse.c
+++ b/drivers/char/atixlmouse.c
@@ -86,25 +86,19 @@ static int release_mouse(struct inode * inode, struct file * file)
{
ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */
free_irq(ATIXL_MOUSE_IRQ, NULL);
- MOD_DEC_USE_COUNT;
return 0;
}
static int open_mouse(struct inode * inode, struct file * file)
{
- /* Lock module as request_irq may sleep */
- MOD_INC_USE_COUNT;
if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt, 0, "ATIXL mouse", NULL))
- {
- MOD_DEC_USE_COUNT;
return -EBUSY;
- }
ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */
return 0;
}
static struct busmouse atixlmouse = {
- ATIXL_BUSMOUSE, "atixl", open_mouse, release_mouse, 0
+ ATIXL_BUSMOUSE, "atixl", THIS_MODULE, open_mouse, release_mouse, 0
};
static int __init atixl_busmouse_init(void)
diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c
index dd9ca78c6..e1cc54e3b 100644
--- a/drivers/char/bttv.c
+++ b/drivers/char/bttv.c
@@ -64,7 +64,6 @@ static struct bttv bttvs[BTTV_MAX];
/* insmod args */
MODULE_PARM(triton1,"i");
-MODULE_PARM(remap,"1-4i");
MODULE_PARM(radio,"1-4i");
MODULE_PARM(card,"1-4i");
MODULE_PARM(pll,"1-4i");
@@ -76,6 +75,7 @@ MODULE_PARM(autoload,"i");
MODULE_PARM(gbuffers,"i");
MODULE_PARM(gbufsize,"i");
+EXPORT_SYMBOL(bttv_get_cardinfo);
EXPORT_SYMBOL(bttv_get_id);
EXPORT_SYMBOL(bttv_gpio_enable);
EXPORT_SYMBOL(bttv_read_gpio);
@@ -91,7 +91,6 @@ static unsigned int bigendian=1;
static unsigned int bigendian=0;
#endif
static int triton1=0;
-static unsigned long remap[BTTV_MAX];
static unsigned int radio[BTTV_MAX];
static unsigned int card[BTTV_MAX] = { 0, 0, 0, 0 };
static unsigned int pll[BTTV_MAX] = { -1, -1, -1, -1};
@@ -123,8 +122,19 @@ static unsigned int autoload = 0;
/* gpio ports (IR for example) */
/* see bttv.h for comments */
+int bttv_get_cardinfo(unsigned int card, int *type, int *cardid)
+{
+ if (card >= bttv_num) {
+ return -1;
+ }
+ *type = bttvs[card].type;
+ *cardid = bttvs[card].cardid;
+ return 0;
+}
+
int bttv_get_id(unsigned int card)
{
+ printk("bttv_get_id is obsolete, use bttv_get_cardinfo instead\n");
if (card >= bttv_num) {
return -1;
}
@@ -180,7 +190,7 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
return 0;
}
-WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card)
+wait_queue_head_t* bttv_get_gpio_queue(unsigned int card)
{
struct bttv *btv;
@@ -467,7 +477,7 @@ static struct i2c_client i2c_client_template = {
NULL
};
-static int __init init_bttv_i2c(struct bttv *btv)
+static int __devinit init_bttv_i2c(struct bttv *btv)
{
/* i2c bit_adapter */
memcpy(&btv->i2c_adap, &i2c_adap_template, sizeof(struct i2c_adapter));
@@ -489,7 +499,7 @@ static int __init init_bttv_i2c(struct bttv *btv)
}
/* read I2C */
-static int __init I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
+static int I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
{
unsigned char buffer = 0;
@@ -514,7 +524,7 @@ static int __init I2CRead(struct bttv *btv, unsigned char addr, char *probe_for)
}
/* write I2C */
-static int __init I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
+static int I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
unsigned char b2, int both)
{
unsigned char buffer[2];
@@ -531,7 +541,7 @@ static int __init I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b
}
/* read EEPROM */
-static void __init readee(struct bttv *btv, unsigned char *eedata, int addr)
+static void __devinit readee(struct bttv *btv, unsigned char *eedata, int addr)
{
int i;
@@ -558,7 +568,7 @@ static struct HAUPPAUGE_TUNER
int id;
char *name;
}
-hauppauge_tuner[] __initdata =
+hauppauge_tuner[] __devinitdata =
{
{ TUNER_ABSENT, "" },
{ TUNER_ABSENT, "External" },
@@ -606,7 +616,7 @@ hauppauge_tuner[] __initdata =
{ TUNER_ABSENT, "Temic 4046FM5" },
};
-static void __init hauppauge_eeprom(struct bttv *btv)
+static void __devinit hauppauge_eeprom(struct bttv *btv)
{
if (eeprom_data[9] < sizeof(hauppauge_tuner)/sizeof(struct HAUPPAUGE_TUNER))
{
@@ -615,11 +625,9 @@ static void __init hauppauge_eeprom(struct bttv *btv)
printk("bttv%d: Hauppauge eeprom: tuner=%s (%d)\n",btv->nr,
hauppauge_tuner[eeprom_data[9]].name,btv->tuner_type);
}
-
- return;
}
-static void __init hauppauge_boot_msp34xx(struct bttv *btv)
+static void __devinit hauppauge_boot_msp34xx(struct bttv *btv)
{
int i;
@@ -655,7 +663,7 @@ static void __init hauppauge_boot_msp34xx(struct bttv *btv)
/* This is basically the same procedure as
* used by Alessandro Rubini in his pxc200
* driver, but using BTTV functions */
-static void __init init_PXC200(struct bttv *btv)
+static void __devinit init_PXC200(struct bttv *btv)
{
static const int vals[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0d, 0x0d,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
@@ -705,7 +713,7 @@ static struct CARD {
unsigned id;
int cardnr;
char *name;
-} cards[] __initdata = {
+} cards[] __devinitdata = {
{ 0x00011002, BTTV_HAUPPAUGE878, "ATI TV Wonder" },
{ 0x00011461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
{ 0x00031461, BTTV_AVPHONE98, "AVerMedia TVPhone98" },
@@ -813,7 +821,7 @@ static struct tvcard tvcards[] =
/* 0x10 */
{ "Pixelview PlayTV (bt878)",
- 3, 1, 0, 2, 0x01fe00, { 2, 0, 1, 1},
+ 3, 1, 0, 2, 0x01fe00, { 2, 3, 1, 1},
{ 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },0,
1,1,1,1,0,0,0,1, PLL_28, -1 },
{ "Leadtek WinView 601",
@@ -910,10 +918,18 @@ static struct tvcard tvcards[] =
{ "ProVideo PV951", /* pic16c54 */
3, 1, 0, 2, 0, { 2, 3, 1, 1}, { 0, 0, 0, 0, 0},0,
0,0,0,0,0,0,0,0, PLL_28, 1 },
+ { "Little OnAir TV",
+ 3, 1, 0, 2, 0xe00b, {2, 3, 1, 1},
+ {0xff9ff6, 0xff9ff6, 0xff1ff7, 0, 0xff3ffc},0,
+ 0,0,0,0,0,0,0,0, PLL_NONE, -1 },
+
+ { "Sigma TVII-FM",
+ 2, 1, 0, -1, 3, {2, 3, 1, 1}, {1, 1, 0, 2, 3},0,
+ 0,0,0,0,0,0,0,0, PLL_NONE, -1 },
};
#define TVCARDS (sizeof(tvcards)/sizeof(struct tvcard))
-static void __init dump_eeprom(struct bttv *btv,int addr)
+static void __devinit dump_eeprom(struct bttv *btv,int addr)
{
int i;
@@ -930,7 +946,7 @@ static void __init dump_eeprom(struct bttv *btv,int addr)
}
}
-static int __init idcard_eeprom(struct bttv *btv)
+static int __devinit idcard_eeprom(struct bttv *btv)
{
unsigned id;
int i,n;
@@ -943,6 +959,7 @@ static int __init idcard_eeprom(struct bttv *btv)
return -1;
/* look for the card */
+ btv->cardid = id;
for (n = -1, i = 0; cards[i].id != 0; i++)
if (cards[i].id == id)
n = i;
@@ -1203,7 +1220,7 @@ static void make_vbitab(struct bttv *btv)
unsigned int *po=(unsigned int *) btv->vbi_odd;
unsigned int *pe=(unsigned int *) btv->vbi_even;
- if (debug)
+ if (debug > 1)
printk("bttv%d: vbi1: po=%08lx pe=%08lx\n",
btv->nr,virt_to_bus(po), virt_to_bus(pe));
@@ -1225,7 +1242,7 @@ static void make_vbitab(struct bttv *btv)
*(pe++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(0x01<<16));
*(pe++)=cpu_to_le32(virt_to_bus(btv->risc_jmp+10));
- if (debug)
+ if (debug > 1)
printk("bttv%d: vbi2: po=%08lx pe=%08lx\n",
btv->nr,virt_to_bus(po), virt_to_bus(pe));
}
@@ -1302,7 +1319,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro,
unsigned long vadr=(unsigned long) vbuf;
int shift, csize;
- if (debug)
+ if (debug > 1)
printk("bttv%d: prisc1: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus(ro), virt_to_bus(re));
@@ -1399,7 +1416,7 @@ static int make_prisctab(struct bttv *btv, unsigned int *ro,
*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
- if (debug)
+ if (debug > 1)
printk("bttv%d: prisc2: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus(ro), virt_to_bus(re));
@@ -1424,7 +1441,7 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro,
if (palette>=VIDEO_PALETTE_PLANAR)
return make_prisctab(btv, ro, re, vbuf, width, height, palette);
- if (debug)
+ if (debug > 1)
printk("bttv%d: vrisc1: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus(ro), virt_to_bus(re));
@@ -1476,7 +1493,7 @@ static int make_vrisctab(struct bttv *btv, unsigned int *ro,
*(re++)=cpu_to_le32(BT848_RISC_JUMP|BT848_RISC_IRQ|(2<<16));
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
- if (debug)
+ if (debug > 1)
printk("bttv%d: vrisc2: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus(ro), virt_to_bus(re));
@@ -1494,7 +1511,7 @@ static void clip_draw_rectangle(unsigned char *clipmap, int x, int y, int w, int
int W, l, r;
int i;
- if (debug)
+ if (debug > 1)
printk("bttv clip: %dx%d+%d+%d\n",w,h,x,y);
/* bitmap is fixed width, 128 bytes (1024 pixels represented) */
@@ -1559,7 +1576,7 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
inter=(btv->win.interlace&1)^1;
width=btv->win.width;
height=btv->win.height;
- if (debug)
+ if (debug > 1)
printk("bttv%d: clip1: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
btv->nr,btv->picture.palette,width,height,bpl,bpp);
if(width > 1023)
@@ -1573,7 +1590,7 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
printk("bttv%d: clip: ro=%08lx re=%08lx\n",
btv->nr,virt_to_bus(ro), virt_to_bus(re));
- if ((clipmap=vmalloc(VIDEO_CLIPMAP_SIZE))==NULL) {
+ if ((clipmap=vmalloc_32(VIDEO_CLIPMAP_SIZE))==NULL) {
/* can't clip, don't generate any risc code */
*(ro++)=cpu_to_le32(BT848_RISC_JUMP);
*(ro++)=cpu_to_le32(btv->bus_vbi_even);
@@ -1668,7 +1685,7 @@ static void make_clip_tab(struct bttv *btv, struct video_clip *cr, int ncr)
*(re++)=cpu_to_le32(BT848_RISC_JUMP);
*(re++)=cpu_to_le32(btv->bus_vbi_odd);
- if (debug)
+ if (debug > 1)
printk("bttv%d: clip2: pal=%d size=%dx%d, bpl=%d bpp=%d\n",
btv->nr,btv->picture.palette,width,height,bpl,bpp);
}
@@ -1734,9 +1751,6 @@ static void bt848_set_geo(struct bttv *btv,
u16 ewidth, eheight, owidth, oheight;
u16 format, bswap;
struct tvnorm *tvn;
- unsigned long flags;
-
- spin_lock_irqsave(&btv->s_lock, flags);
tvn=&tvnorms[btv->win.norm];
@@ -1789,8 +1803,6 @@ static void bt848_set_geo(struct bttv *btv,
btwrite(format, BT848_COLOR_FMT);
btwrite(bswap | BT848_COLOR_CTL_GAMMA, BT848_COLOR_CTL);
-
- spin_unlock_irqrestore(&btv->s_lock, flags);
}
@@ -1847,7 +1859,6 @@ static void bt848_set_winsize(struct bttv *btv)
/*
* Grab into virtual memory.
- * Currently only does double buffering. Do we need more?
*/
static int vgrab(struct bttv *btv, struct video_mmap *mp)
@@ -1904,16 +1915,16 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
btv->gbuf[mp->frame].ro = 0;
#endif
- if (btv->gq_in == btv->gq_out) {
+ if (-1 == btv->gq_grab && btv->gq_in == btv->gq_out) {
btv->gq_start = 1;
btv->risc_jmp[12]=cpu_to_le32(BT848_RISC_JUMP|(0x8<<16)|BT848_RISC_IRQ);
}
btv->gqueue[btv->gq_in++] = mp->frame;
btv->gq_in = btv->gq_in % MAX_GBUFFERS;
- spin_unlock_irqrestore(&btv->s_lock, flags);
btor(3, BT848_CAP_CTL);
btor(3, BT848_GPIO_DMA_CTL);
+ spin_unlock_irqrestore(&btv->s_lock, flags);
return 0;
}
@@ -1927,39 +1938,43 @@ static long bttv_read(struct video_device *v, char *buf, unsigned long count, in
{
struct bttv *btv= (struct bttv *)v;
int q,todo;
+ DECLARE_WAITQUEUE(wait, current);
/* BROKEN: RETURNS VBI WHEN IT SHOULD RETURN GRABBED VIDEO FRAME */
todo=count;
while (todo && todo>(q=VBIBUF_SIZE-btv->vbip))
{
- unsigned long flags;
-
if(copy_to_user((void *) buf, (void *) btv->vbibuf+btv->vbip, q))
return -EFAULT;
todo-=q;
buf+=q;
- spin_lock_irqsave(&btv->s_lock, flags);
+ add_wait_queue(&btv->vbiq, &wait);
+ current->state = TASK_INTERRUPTIBLE;
if (todo && q==VBIBUF_SIZE-btv->vbip)
{
if(nonblock)
{
- spin_unlock_irqrestore(&btv->s_lock, flags);
+ remove_wait_queue(&btv->vbiq, &wait);
+ current->state = TASK_RUNNING;
if(count==todo)
return -EWOULDBLOCK;
return count-todo;
}
- spin_unlock_irqrestore(&btv->s_lock, flags);
- interruptible_sleep_on(&btv->vbiq);
+ schedule();
if(signal_pending(current))
{
+ remove_wait_queue(&btv->vbiq, &wait);
+ current->state = TASK_RUNNING;
+
if(todo==count)
return -EINTR;
else
return count-todo;
}
- } else
- spin_unlock_irqrestore(&btv->s_lock, flags);
+ }
+ remove_wait_queue(&btv->vbiq, &wait);
+ current->state = TASK_RUNNING;
}
if (todo)
{
@@ -1980,9 +1995,11 @@ static inline void burst(int on)
static void bt848_restart(struct bttv *btv)
{
+ unsigned long irq_flags;
+
if (verbose)
printk("bttv%d: resetting chip\n",btv->nr);
- btwrite(~0x0UL, BT848_INT_STAT);
+ btwrite(0xfffffUL, BT848_INT_STAT);
btand(~15, BT848_GPIO_DMA_CTL);
btwrite(0, BT848_SRESET);
btwrite(virt_to_bus(btv->risc_jmp+2),
@@ -1994,8 +2011,10 @@ static void bt848_restart(struct bttv *btv)
btv->errors = 0;
btv->needs_restart = 0;
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
bt848_set_geo(btv,0);
bt848_set_risc_jmps(btv,-1);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
}
/*
@@ -2042,13 +2061,16 @@ static int bttv_open(struct video_device *dev, int flags)
static void bttv_close(struct video_device *dev)
{
struct bttv *btv=(struct bttv *)dev;
+ unsigned long irq_flags;
down(&btv->lock);
btv->user--;
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
btv->scr_on = 0;
btv->risc_cap_odd = 0;
btv->risc_cap_even = 0;
bt848_set_risc_jmps(btv,-1);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
/*
* A word of warning. At this point the chip
@@ -2133,9 +2155,11 @@ static inline void bt848_sat_v(struct bttv *btv, unsigned long data)
static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
{
struct bttv *btv=(struct bttv *)dev;
+ unsigned long irq_flags;
int i,ret = 0;
- if (debug) printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd);
+ if (debug > 1)
+ printk("bttv%d: ioctl 0x%x\n",btv->nr,cmd);
switch (cmd) {
case VIDIOCGCAP:
@@ -2206,7 +2230,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if (btv->win.norm != v.norm) {
btv->win.norm = v.norm;
make_vbitab(btv);
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
bt848_set_winsize(btv);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
}
up(&btv->lock);
return 0;
@@ -2248,7 +2274,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
down(&btv->lock);
set_pll(btv);
make_vbitab(btv);
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
bt848_set_winsize(btv);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
up(&btv->lock);
}
return 0;
@@ -2289,12 +2317,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(copy_from_user(&vw,arg,sizeof(vw)))
return -EFAULT;
+ down(&btv->lock);
if(vw.flags || vw.width < 16 || vw.height < 16)
{
- down(&btv->lock);
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
btv->scr_on = 0;
bt848_set_risc_jmps(btv,-1);
- up(&btv->lock);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
return -EINVAL;
}
if (btv->win.bpp < 4)
@@ -2302,18 +2331,17 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
vw.x = (vw.x + 3) & ~3;
vw.width &= ~3;
}
- down(&btv->lock);
if (btv->needs_restart)
bt848_restart(btv);
btv->win.x=vw.x;
btv->win.y=vw.y;
btv->win.width=vw.width;
btv->win.height=vw.height;
-
+
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
bt848_set_risc_jmps(btv,0);
-
bt848_set_winsize(btv);
- up(&btv->lock);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
/*
* Do any clips.
@@ -2337,11 +2365,12 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EFAULT;
}
}
- down(&btv->lock);
make_clip_tab(btv, vcp, vw.clipcount);
if (vw.clipcount != 0)
vfree(vcp);
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
bt848_set_risc_jmps(btv,-1);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
up(&btv->lock);
return 0;
}
@@ -2370,13 +2399,13 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
return -EINVAL;
if (btv->win.width==0 || btv->win.height==0)
return -EINVAL;
- down(&btv->lock);
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
if (v == 1 && btv->win.vidadr != 0)
btv->scr_on = 1;
if (v == 0)
btv->scr_on = 0;
bt848_set_risc_jmps(btv,-1);
- up(&btv->lock);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
return 0;
}
case VIDIOCGFBUF:
@@ -2500,9 +2529,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
if(!(v.flags&VIDEO_AUDIO_MUTE))
audio(btv, AUDIO_UNMUTE, 1);
- up(&btv->lock);
call_i2c_clients(btv,cmd,&v);
- down(&btv->lock);
if (btv->type == BTTV_TERRATV) {
unsigned int con = 0;
@@ -2554,6 +2581,9 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
}
case VIDIOCSYNC:
+ {
+ DECLARE_WAITQUEUE(wait, current);
+
if(copy_from_user((void *)&i,arg,sizeof(int)))
return -EFAULT;
if (i < 0 || i >= gbuffers)
@@ -2563,13 +2593,20 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
ret = -EINVAL;
break;
case GBUFFER_GRABBING:
+ add_wait_queue(&btv->capq, &wait);
+ current->state = TASK_INTERRUPTIBLE;
while(btv->gbuf[i].stat==GBUFFER_GRABBING) {
if (debug)
printk("bttv%d: cap sync: sleep on %d\n",btv->nr,i);
- interruptible_sleep_on(&btv->capq);
- if(signal_pending(current))
+ schedule();
+ if(signal_pending(current)) {
+ remove_wait_queue(&btv->capq, &wait);
+ current->state = TASK_RUNNING;
return -EINTR;
+ }
}
+ remove_wait_queue(&btv->capq, &wait);
+ current->state = TASK_RUNNING;
/* fall throuth */
case GBUFFER_DONE:
case GBUFFER_ERROR:
@@ -2584,6 +2621,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
up(&btv->lock);
}
return ret;
+ }
case BTTV_FIELDNR:
if(copy_to_user((void *) arg, (void *) &btv->last_field,
@@ -2602,7 +2640,6 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
btv->pll.pll_ofreq = p.pll_ofreq;
btv->pll.pll_crystal = p.pll_crystal;
up(&btv->lock);
-
break;
}
@@ -2749,12 +2786,11 @@ static long vbi_read(struct video_device *v, char *buf, unsigned long count,
{
struct bttv *btv=(struct bttv *)(v-2);
int q,todo;
+ DECLARE_WAITQUEUE(wait, current);
todo=count;
while (todo && todo>(q=VBIBUF_SIZE-btv->vbip))
{
- unsigned long flags;
-
if (btv->needs_restart) {
down(&btv->lock);
bt848_restart(btv);
@@ -2765,27 +2801,31 @@ static long vbi_read(struct video_device *v, char *buf, unsigned long count,
todo-=q;
buf+=q;
- spin_lock_irqsave(&btv->s_lock, flags);
+ add_wait_queue(&btv->vbiq, &wait);
+ current->state = TASK_INTERRUPTIBLE;
if (todo && q==VBIBUF_SIZE-btv->vbip)
{
if(nonblock)
{
- spin_unlock_irqrestore(&btv->s_lock, flags);
+ remove_wait_queue(&btv->vbiq, &wait);
+ current->state = TASK_RUNNING;
if(count==todo)
return -EWOULDBLOCK;
return count-todo;
}
- spin_unlock_irqrestore(&btv->s_lock, flags);
- interruptible_sleep_on(&btv->vbiq);
+ schedule();
if(signal_pending(current))
{
+ remove_wait_queue(&btv->vbiq, &wait);
+ current->state = TASK_RUNNING;
if(todo==count)
return -EINTR;
else
return count-todo;
}
- } else
- spin_unlock_irqrestore(&btv->s_lock, flags);
+ }
+ remove_wait_queue(&btv->vbiq, &wait);
+ current->state = TASK_RUNNING;
}
if (todo)
{
@@ -2813,15 +2853,18 @@ static unsigned int vbi_poll(struct video_device *dev, struct file *file,
static int vbi_open(struct video_device *dev, int flags)
{
struct bttv *btv=(struct bttv *)(dev-2);
+ unsigned long irq_flags;
MOD_INC_USE_COUNT;
-
down(&btv->lock);
if (btv->needs_restart)
bt848_restart(btv);
+ set_pll(btv);
btv->vbip=VBIBUF_SIZE;
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
btv->vbi_on = 1;
bt848_set_risc_jmps(btv,-1);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
up(&btv->lock);
return 0;
@@ -2830,12 +2873,12 @@ static int vbi_open(struct video_device *dev, int flags)
static void vbi_close(struct video_device *dev)
{
struct bttv *btv=(struct bttv *)(dev-2);
+ unsigned long irq_flags;
- down(&btv->lock);
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
btv->vbi_on = 0;
bt848_set_risc_jmps(btv,-1);
- up(&btv->lock);
-
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
MOD_DEC_USE_COUNT;
}
@@ -3018,7 +3061,7 @@ static struct video_device radio_template=
#define TRITON_PEER_CONCURRENCY (1<<3)
-static void __init handle_chipset(void)
+static void __devinit handle_chipset(void)
{
struct pci_dev *dev = NULL;
@@ -3050,7 +3093,7 @@ static void __init handle_chipset(void)
/* can tda9855.c handle this too maybe? */
-static void __init init_tda9840(struct bttv *btv)
+static void __devinit init_tda9840(struct bttv *btv)
{
/* Horrible Hack */
I2CWrite(btv, I2C_TDA9840, TDA9840_SW, 0x2a, 1); /* sound mode switching */
@@ -3066,12 +3109,11 @@ static void __init init_tda9840(struct bttv *btv)
/* Figure out card and tuner type */
-static void __init idcard(struct bttv *btv)
+static void __devinit idcard(struct bttv *btv)
{
int type,eeprom = 0;
btwrite(0, BT848_GPIO_OUT_EN);
- DEBUG(printk(KERN_DEBUG "bttv%d: GPIO: 0x%08x\n", btv->nr, btread(BT848_GPIO_DATA)));
/* Default the card to the user-selected one. */
if (card[btv->nr] >= 0 && card[btv->nr] < TVCARDS)
@@ -3114,7 +3156,6 @@ static void __init idcard(struct bttv *btv)
(btv->id==848 && btv->revision==0x12) ? "A" : "",
tvcards[btv->type].name);
printk(KERN_INFO "bttv%d: model: %s\n",btv->nr,btv->video_dev.name);
-
/* board specific initialisations */
if (btv->type == BTTV_MIRO || btv->type == BTTV_MIROPRO) {
@@ -3228,10 +3269,6 @@ static void __init idcard(struct bttv *btv)
static void bt848_set_risc_jmps(struct bttv *btv, int flags)
{
- unsigned long irq_flags;
-
- spin_lock_irqsave(&btv->s_lock, irq_flags);
-
if (-1 == flags) {
/* defaults */
flags = 0;
@@ -3241,8 +3278,9 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags)
flags |= 0x0c;
}
- if (debug) printk("bttv%d: set_risc_jmp %08lx:",
- btv->nr,virt_to_bus(btv->risc_jmp));
+ if (debug > 1)
+ printk("bttv%d: set_risc_jmp %08lx:",
+ btv->nr,virt_to_bus(btv->risc_jmp));
/* Sync to start of odd field */
btv->risc_jmp[0]=cpu_to_le32(BT848_RISC_SYNC|BT848_RISC_RESYNC
@@ -3252,24 +3290,29 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags)
/* Jump to odd vbi sub */
btv->risc_jmp[2]=cpu_to_le32(BT848_RISC_JUMP|(0xd<<20));
if (flags&8) {
- if (debug) printk(" ev=%08lx",virt_to_bus(btv->vbi_odd));
+ if (debug > 1)
+ printk(" ev=%08lx",virt_to_bus(btv->vbi_odd));
btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->vbi_odd));
} else {
- if (debug) printk(" -----------");
+ if (debug > 1)
+ printk(" -----------");
btv->risc_jmp[3]=cpu_to_le32(virt_to_bus(btv->risc_jmp+4));
}
/* Jump to odd sub */
btv->risc_jmp[4]=cpu_to_le32(BT848_RISC_JUMP|(0xe<<20));
if (0 != btv->risc_cap_odd) {
- if (debug) printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd);
+ if (debug > 1)
+ printk(" e%d=%08x",btv->gq_grab,btv->risc_cap_odd);
flags |= 3;
btv->risc_jmp[5]=cpu_to_le32(btv->risc_cap_odd);
} else if (flags&2) {
- if (debug) printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd));
+ if (debug > 1)
+ printk(" eo=%08lx",virt_to_bus(btv->risc_scr_odd));
btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_scr_odd));
} else {
- if (debug) printk(" -----------");
+ if (debug > 1)
+ printk(" -----------");
btv->risc_jmp[5]=cpu_to_le32(virt_to_bus(btv->risc_jmp+6));
}
@@ -3282,24 +3325,29 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags)
/* Jump to even vbi sub */
btv->risc_jmp[8]=cpu_to_le32(BT848_RISC_JUMP);
if (flags&4) {
- if (debug) printk(" ov=%08lx",virt_to_bus(btv->vbi_even));
+ if (debug > 1)
+ printk(" ov=%08lx",virt_to_bus(btv->vbi_even));
btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->vbi_even));
} else {
- if (debug) printk(" -----------");
+ if (debug > 1)
+ printk(" -----------");
btv->risc_jmp[9]=cpu_to_le32(virt_to_bus(btv->risc_jmp+10));
}
/* Jump to even sub */
btv->risc_jmp[10]=cpu_to_le32(BT848_RISC_JUMP|(8<<20));
if (0 != btv->risc_cap_even) {
- if (debug) printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even);
+ if (debug > 1)
+ printk(" o%d=%08x",btv->gq_grab,btv->risc_cap_even);
flags |= 3;
btv->risc_jmp[11]=cpu_to_le32(btv->risc_cap_even);
} else if (flags&1) {
- if (debug) printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even));
+ if (debug > 1)
+ printk(" oo=%08lx",virt_to_bus(btv->risc_scr_even));
btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_scr_even));
} else {
- if (debug) printk(" -----------");
+ if (debug > 1)
+ printk(" -----------");
btv->risc_jmp[11]=cpu_to_le32(virt_to_bus(btv->risc_jmp+12));
}
@@ -3311,18 +3359,17 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags)
btv->risc_jmp[13]=cpu_to_le32(virt_to_bus(btv->risc_jmp));
/* enable cpaturing and DMA */
- if (debug) printk(" flags=0x%x dma=%s\n",
- flags,(flags&0x0f) ? "on" : "off");
+ if (debug > 1)
+ printk(" flags=0x%x dma=%s\n",
+ flags,(flags&0x0f) ? "on" : "off");
btaor(flags, ~0x0f, BT848_CAP_CTL);
if (flags&0x0f)
bt848_dma(btv, 3);
else
bt848_dma(btv, 0);
-
- spin_unlock_irqrestore(&btv->s_lock, irq_flags);
}
-static int __init init_video_dev(struct bttv *btv)
+static int __devinit init_video_dev(struct bttv *btv)
{
memcpy(&btv->video_dev,&bttv_template, sizeof(bttv_template));
memcpy(&btv->vbi_dev,&vbi_template, sizeof(vbi_template));
@@ -3349,9 +3396,10 @@ static int __init init_video_dev(struct bttv *btv)
return 1;
}
-static int __init init_bt848(struct bttv *btv)
+static int __devinit init_bt848(struct bttv *btv)
{
int j;
+ unsigned long irq_flags;
btv->user=0;
init_MUTEX(&btv->lock);
@@ -3412,14 +3460,13 @@ static int __init init_bt848(struct bttv *btv)
return -1;
if (!(btv->risc_jmp =(unsigned int *) kmalloc(2048, GFP_KERNEL)))
return -1;
- DEBUG(printk(KERN_DEBUG "risc_jmp: %p\n",btv->risc_jmp));
btv->vbi_odd=btv->risc_jmp+16;
btv->vbi_even=btv->vbi_odd+256;
btv->bus_vbi_odd=virt_to_bus(btv->risc_jmp+12);
btv->bus_vbi_even=virt_to_bus(btv->risc_jmp+6);
btwrite(virt_to_bus(btv->risc_jmp+2), BT848_RISC_STRT_ADD);
- btv->vbibuf=(unsigned char *) vmalloc(VBIBUF_SIZE);
+ btv->vbibuf=(unsigned char *) vmalloc_32(VBIBUF_SIZE);
if (!btv->vbibuf)
return -1;
if (!(btv->gbuf = kmalloc(sizeof(struct bttv_gbuf)*gbuffers,GFP_KERNEL)))
@@ -3475,7 +3522,7 @@ static int __init init_bt848(struct bttv *btv)
btwrite(0x00, BT848_O_SCLOOP);
/* clear interrupt status */
- btwrite(~0x0UL, BT848_INT_STAT);
+ btwrite(0xfffffUL, BT848_INT_STAT);
/* set interrupt mask */
btwrite(btv->triton1|
@@ -3489,8 +3536,10 @@ static int __init init_bt848(struct bttv *btv)
BT848_INT_MASK);
make_vbitab(btv);
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
bt848_set_risc_jmps(btv,-1);
-
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
+
/*
* Now add the template and register the device unit.
*/
@@ -3505,7 +3554,8 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
u32 dstat;
int count,i;
struct bttv *btv;
-
+ unsigned long irq_flags;
+
btv=(struct bttv *)dev_id;
count=0;
while (1)
@@ -3515,6 +3565,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
astat=stat&btread(BT848_INT_MASK);
if (!astat)
return;
+ btwrite(astat,BT848_INT_STAT);
IDEBUG(printk ("bttv%d: astat=%08x\n", btv->nr, astat));
IDEBUG(printk ("bttv%d: stat=%08x\n", btv->nr, stat));
@@ -3550,15 +3601,18 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btread(BT848_RISC_COUNT));
btv->errors++;
if (btv->errors < BTTV_ERRORS) {
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
btand(~15, BT848_GPIO_DMA_CTL);
btwrite(virt_to_bus(btv->risc_jmp+2),
BT848_RISC_STRT_ADD);
bt848_set_geo(btv,0);
bt848_set_risc_jmps(btv,-1);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
} else {
if (verbose)
printk("bttv%d: aiee: error loops\n",btv->nr);
/* cancel all outstanding grab requests */
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
btv->gq_in = 0;
btv->gq_out = 0;
btv->gq_grab = -1;
@@ -3569,8 +3623,9 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btv->risc_cap_odd = 0;
btv->risc_cap_even = 0;
bt848_set_risc_jmps(btv,0);
-
btv->needs_restart = 1;
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
+
wake_up_interruptible(&btv->vbiq);
wake_up_interruptible(&btv->capq);
}
@@ -3596,6 +3651,7 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
if (debug)
printk("bttv%d: cap irq: done %d\n",btv->nr,btv->gq_grab);
do_gettimeofday(&btv->gbuf[btv->gq_grab].tv);
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
btv->gbuf[btv->gq_grab].stat = GBUFFER_DONE;
btv->gq_grab = -1;
if (btv->gq_in != btv->gq_out)
@@ -3618,22 +3674,25 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
btwrite(btv->fb_color_ctl | BT848_COLOR_CTL_GAMMA,
BT848_COLOR_CTL);
}
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
wake_up_interruptible(&btv->capq);
break;
}
if (stat&(8<<28))
{
+ spin_lock_irqsave(&btv->s_lock, irq_flags);
btv->gq_start = 0;
btv->gq_grab = btv->gqueue[btv->gq_out++];
btv->gq_out = btv->gq_out % MAX_GBUFFERS;
if (debug)
- printk("bttv%d: cap irq: capture %d\n",btv->nr,btv->gq_grab);
+ printk("bttv%d: cap irq: capture %d [start]\n",btv->nr,btv->gq_grab);
btv->risc_cap_odd = btv->gbuf[btv->gq_grab].ro;
btv->risc_cap_even = btv->gbuf[btv->gq_grab].re;
bt848_set_risc_jmps(btv,-1);
bt848_set_geo(btv,0);
btwrite(BT848_COLOR_CTL_GAMMA,
BT848_COLOR_CTL);
+ spin_unlock_irqrestore(&btv->s_lock, irq_flags);
}
}
if (astat&BT848_INT_OCERR)
@@ -3676,9 +3735,6 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
{
IDEBUG(printk ("bttv%d: IRQ_I2CDONE\n", btv->nr));
}
-
- btwrite(astat,BT848_INT_STAT);
-
count++;
if (count > 10)
printk (KERN_WARNING "bttv%d: irq loop %d\n",
@@ -3698,11 +3754,11 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
* Scan for a Bt848 card, request the irq and map the io memory
*/
-static void __init bttv_remove(struct pci_dev *pci_dev)
+static void __devinit bttv_remove(struct pci_dev *pci_dev)
{
u8 command;
int j;
- struct bttv *btv = pci_dev->driver_data;
+ struct bttv *btv = PCI_GET_DRIVER_DATA(pci_dev);
/* unregister i2c_bus */
i2c_bit_del_bus(&btv->i2c_adap);
@@ -3767,7 +3823,7 @@ static void __init bttv_remove(struct pci_dev *pci_dev)
}
-static int __init bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
+static int __devinit bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
{
int result;
unsigned char command;
@@ -3788,20 +3844,17 @@ static int __init bttv_probe(struct pci_dev *dev, const struct pci_device_id *pc
btv->vbi_even=NULL;
init_waitqueue_head(&btv->vbiq);
init_waitqueue_head(&btv->capq);
- init_waitqueue_head(&btv->capqo);
- init_waitqueue_head(&btv->capqe);
btv->vbip=VBIBUF_SIZE;
-
- init_waitqueue_head(&btv->gpioq);
btv->s_lock = SPIN_LOCK_UNLOCKED;
+ init_waitqueue_head(&btv->gpioq);
btv->shutdown=0;
btv->id=dev->device;
btv->irq=dev->irq;
- btv->bt848_adr=pci_resource_start(dev, 0);
+ btv->bt848_adr=pci_resource_start(dev,0);
if (pci_enable_device(dev))
return -EIO;
- if (!request_mem_region(btv->bt848_adr,
+ if (!request_mem_region(pci_resource_start(dev,0),
pci_resource_len(dev,0),
"bttv")) {
return -EBUSY;
@@ -3871,24 +3924,23 @@ static int __init bttv_probe(struct pci_dev *dev, const struct pci_device_id *pc
}
}
- dev->driver_data = btv;
+ PCI_SET_DRIVER_DATA(dev,btv);
if(init_bt848(btv) < 0) {
bttv_remove(dev);
return -EIO;
}
-
bttv_num++;
return 0;
fail:
- release_mem_region(btv->bt848_adr,
+ release_mem_region(pci_resource_start(btv->dev,0),
pci_resource_len(btv->dev,0));
return result;
}
-static struct pci_device_id bttv_pci_tbl[] __initdata = {
+static struct pci_device_id bttv_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
@@ -3903,13 +3955,13 @@ static struct pci_device_id bttv_pci_tbl[] __initdata = {
MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
static struct pci_driver bttv_pci_driver = {
- name:"bttv",
- id_table:bttv_pci_tbl,
- probe:bttv_probe,
- remove:bttv_remove,
+ name: "bttv",
+ id_table: bttv_pci_tbl,
+ probe: bttv_probe,
+ remove: bttv_remove,
};
-static int __init bttv_init_module(void)
+int bttv_init_module(void)
{
bttv_num = 0;
@@ -3930,10 +3982,10 @@ static int __init bttv_init_module(void)
return pci_module_init(&bttv_pci_driver);
}
-static void __exit bttv_cleanup_module(void)
+void bttv_cleanup_module(void)
{
pci_unregister_driver(&bttv_pci_driver);
- return;
+ return;
}
module_init(bttv_init_module);
diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h
index 3f4229fe8..9189bfa77 100644
--- a/drivers/char/bttv.h
+++ b/drivers/char/bttv.h
@@ -21,7 +21,12 @@
#ifndef _BTTV_H_
#define _BTTV_H_
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,28)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,31)
+
+#ifndef PCI_GET_DRIVER_DATA
+# define PCI_GET_DRIVER_DATA(pdev) ((pdev)->driver_data)
+# define PCI_SET_DRIVER_DATA(pdev,data) (((pdev)->driver_data) = (data))
+#endif /* PCI_GET_DRIVER_DATA */
#include <linux/types.h>
#include <linux/wait.h>
@@ -32,12 +37,13 @@
#include "audiochip.h"
#include "bt848.h"
-#define WAIT_QUEUE wait_queue_head_t
-
-/* returns card type,
+/* returns card type + card ID (for bt878-based ones)
for possible values see lines below beginning with #define BTTV_UNKNOWN
returns negative value if error ocurred
*/
+extern int bttv_get_cardinfo(unsigned int card, int *type, int *cardid);
+
+/* obsolete, use bttv_get_cardinfo instead */
extern int bttv_get_id(unsigned int card);
/* sets GPOE register (BT848_GPIO_OUT_EN) to new value:
@@ -68,7 +74,7 @@ extern int bttv_write_gpio(unsigned int card,
WARNING: because there is no buffer for GPIO data, one MUST
process data ASAP
*/
-extern WAIT_QUEUE* bttv_get_gpio_queue(unsigned int card);
+extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
#ifndef O_NONCAP
@@ -130,6 +136,7 @@ struct bttv {
struct video_picture picture; /* Current picture params */
struct video_audio audio_dev; /* Current audio params */
+ spinlock_t s_lock;
struct semaphore lock;
int user;
int capuser;
@@ -143,8 +150,6 @@ struct bttv {
int tuner_type;
int channel;
-
- spinlock_t s_lock;
unsigned int nr;
unsigned short id;
@@ -160,6 +165,7 @@ struct bttv {
struct bttv_window win;
int fb_color_ctl;
int type; /* card type */
+ int cardid;
int audio; /* audio mode */
int audio_chip; /* set to one of the chips supported by bttv.c */
int radio;
@@ -169,10 +175,8 @@ struct bttv {
u32 *vbi_even;
u32 bus_vbi_even;
u32 bus_vbi_odd;
- WAIT_QUEUE vbiq;
- WAIT_QUEUE capq;
- WAIT_QUEUE capqo;
- WAIT_QUEUE capqe;
+ wait_queue_head_t vbiq;
+ wait_queue_head_t capq;
int vbip;
u32 *risc_scr_odd;
@@ -198,7 +202,7 @@ struct bttv {
int errors;
int needs_restart;
- WAIT_QUEUE gpioq;
+ wait_queue_head_t gpioq;
int shutdown;
};
#endif
@@ -277,6 +281,8 @@ extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
#define BTTV_STB2 0x28
#define BTTV_AVPHONE98 0x29
#define BTTV_PV951 0x2a
+#define BTTV_ONAIR_TV 0x2b
+#define BTTV_SIGMA_TVII_FM 0x2c
#define PLL_NONE 0
#define PLL_28 1
diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c
index 1b09081c1..bc8345cff 100644
--- a/drivers/char/busmouse.c
+++ b/drivers/char/busmouse.c
@@ -110,8 +110,7 @@ void busmouse_add_movementbuttons(int mousedev, int dx, int dy, int buttons)
if (changed) {
wake_up(&mse->wait);
- if (mse->fasyncptr)
- kill_fasync(mse->fasyncptr, SIGIO, POLL_IN);
+ kill_fasync(&mse->fasyncptr, SIGIO, POLL_IN);
}
}
@@ -171,13 +170,13 @@ static int busmouse_release(struct inode *inode, struct file *file)
busmouse_fasync(-1, file, 0);
if (--mse->active == 0) {
- if (mse->ops &&
- mse->ops->release)
- ret = mse->ops->release(inode, file);
-
+ if (mse->ops) {
+ if (mse->ops->release)
+ ret = mse->ops->release(inode, file);
+ if (mse->ops->owner)
+ __MOD_DEC_USE_COUNT(mse->ops->owner);
+ }
mse->ready = 0;
-
- MOD_DEC_USE_COUNT;
}
return ret;
@@ -192,16 +191,20 @@ static int busmouse_open(struct inode *inode, struct file *file)
mousedev = DEV_TO_MOUSE(inode->i_rdev);
if (mousedev >= NR_MICE)
return -EINVAL;
-
+
down(&mouse_sem);
mse = busmouse_data[mousedev];
if (!mse)
/* shouldn't happen, but... */
goto end;
- if (mse->ops &&
- mse->ops->open)
+ if (mse->ops && mse->ops->owner)
+ __MOD_INC_USE_COUNT(mse->ops->owner);
+ if (mse->ops && mse->ops->open) {
ret = mse->ops->open(inode, file);
+ if (ret && mse->ops->owner)
+ __MOD_DEC_USE_COUNT(mse->ops->owner);
+ }
if (ret)
goto end;
@@ -211,8 +214,6 @@ static int busmouse_open(struct inode *inode, struct file *file)
if (mse->active++)
goto end;
- MOD_INC_USE_COUNT;
-
spin_lock_irq(&mse->lock);
mse->ready = 0;
@@ -333,6 +334,7 @@ static unsigned int busmouse_poll(struct file *file, poll_table *wait)
struct file_operations busmouse_fops=
{
+ owner: THIS_MODULE,
read: busmouse_read,
write: busmouse_write,
poll: busmouse_poll,
diff --git a/drivers/char/busmouse.h b/drivers/char/busmouse.h
index 641e66d49..487c4820d 100644
--- a/drivers/char/busmouse.h
+++ b/drivers/char/busmouse.h
@@ -11,6 +11,7 @@
struct busmouse {
int minor;
const char *name;
+ struct module *owner;
int (*open)(struct inode * inode, struct file * file);
int (*release)(struct inode * inode, struct file * file);
int init_button_state;
diff --git a/drivers/char/buz.c b/drivers/char/buz.c
index cbf085e9e..299a4f8ca 100644
--- a/drivers/char/buz.c
+++ b/drivers/char/buz.c
@@ -48,6 +48,7 @@
#include <linux/types.h>
#include <linux/wrapper.h>
#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
#include <linux/videodev.h>
diff --git a/drivers/char/c-qcam.c b/drivers/char/c-qcam.c
index 1e0582bdf..fa96cc925 100644
--- a/drivers/char/c-qcam.c
+++ b/drivers/char/c-qcam.c
@@ -12,9 +12,15 @@
* probe=1 -- use IEEE-1284 autoprobe data only (default)
* probe=2 -- probe aggressively for cameras
*
+ * force_rgb=1 -- force data format to RGB (default is BGR)
+ *
* The parport parameter controls which parports will be scanned.
* Scanning all parports causes some printers to print a garbage page.
* -- March 14, 1999 Billy Donahue <billy@escape.com>
+ *
+ * Fixed data format to BGR, added force_rgb parameter. Added missing
+ * parport_unregister_driver() on module removal.
+ * -- May 28, 2000 Claudio Matsuoka <claudio@conectiva.com>
*/
#include <linux/module.h>
@@ -62,6 +68,7 @@ struct qcam_device {
static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
static int probe = 2;
+static int force_rgb = 0;
static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
{
@@ -278,6 +285,7 @@ static void qc_setup(struct qcam_device *q)
static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes)
{
unsigned int bytes = 0;
+
qcam_set_ack(q, 0);
if (q->bidirectional)
{
@@ -285,6 +293,8 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u
while (bytes < nbytes)
{
unsigned int lo1, hi1, lo2, hi2;
+ unsigned char r, g, b;
+
if (qcam_await_ready2(q, 1)) return bytes;
lo1 = parport_read_data(q->pport) >> 1;
hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
@@ -293,17 +303,30 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u
lo2 = parport_read_data(q->pport) >> 1;
hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
qcam_set_ack(q, 0);
- buf[bytes++] = (lo1 | ((hi1 & 1)<<7));
- buf[bytes++] = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1);
- buf[bytes++] = (lo2 | ((hi2 & 1)<<7));
+ r = (lo1 | ((hi1 & 1)<<7));
+ g = ((hi1 & 0x1e)<<3) | ((hi2 & 0x1e)>>1);
+ b = (lo2 | ((hi2 & 1)<<7));
+ if (force_rgb) {
+ buf[bytes++] = r;
+ buf[bytes++] = g;
+ buf[bytes++] = b;
+ } else {
+ buf[bytes++] = b;
+ buf[bytes++] = g;
+ buf[bytes++] = r;
+ }
}
}
else
{
/* It's a unidirectional port */
+ int i = 0, n = bytes;
+ unsigned char rgb[3];
+
while (bytes < nbytes)
{
unsigned int hi, lo;
+
if (qcam_await_ready1(q, 1)) return bytes;
hi = (parport_read_status(q->pport) & 0xf0);
qcam_set_ack(q, 1);
@@ -311,7 +334,23 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u
lo = (parport_read_status(q->pport) & 0xf0);
qcam_set_ack(q, 0);
/* flip some bits */
- buf[bytes++] = (hi | (lo >> 4)) ^ 0x88;
+ rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
+ if (i >= 2) {
+get_fragment:
+ if (force_rgb) {
+ buf[n++] = rgb[0];
+ buf[n++] = rgb[1];
+ buf[n++] = rgb[2];
+ } else {
+ buf[n++] = rgb[2];
+ buf[n++] = rgb[1];
+ buf[n++] = rgb[0];
+ }
+ }
+ }
+ if (i) {
+ i = 0;
+ goto get_fragment;
}
}
return bytes;
@@ -408,8 +447,13 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
if (current->need_resched)
schedule();
} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
- if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
- printk("qcam: bad EOF\n");
+ if (force_rgb) {
+ if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
+ printk("qcam: bad EOF\n");
+ } else {
+ if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
+ printk("qcam: bad EOF\n");
+ }
qcam_set_ack(q, 0);
if (qcam_await_ready1(q, 1))
{
@@ -437,8 +481,13 @@ static long qc_capture(struct qcam_device *q, char *buf, unsigned long len)
schedule();
} while (l && tmpbuf[0] == 0x7e);
l = qcam_read_bytes(q, tmpbuf+1, 2);
- if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
- printk("qcam: bad EOF\n");
+ if (force_rgb) {
+ if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
+ printk("qcam: bad EOF\n");
+ } else {
+ if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
+ printk("qcam: bad EOF\n");
+ }
}
qcam_write_data(q, 0);
@@ -829,19 +878,24 @@ static int __init cqcam_init (void)
return parport_register_driver(&cqcam_driver);
}
-MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
-MODULE_DESCRIPTION(BANNER);
-MODULE_PARM_DESC(parport ,"parport=<auto|n[,n]...> for port detection method \n\
-probe=<0|1|2> # for camera detection method");
-MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i");
-MODULE_PARM(probe, "i");
-
static void __exit cqcam_cleanup (void)
{
unsigned int i;
+
for (i = 0; i < num_cams; i++)
close_cqcam(qcams[i]);
+
+ parport_unregister_driver(&cqcam_driver);
}
+MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
+MODULE_DESCRIPTION(BANNER);
+MODULE_PARM_DESC(parport ,"parport=<auto|n[,n]...> for port detection method\n\
+probe=<0|1|2> for camera detection method\n\
+force_rgb=<0|1> for RGB data format (default BGR)");
+MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "i");
+MODULE_PARM(probe, "i");
+MODULE_PARM(force_rgb, "i");
+
module_init(cqcam_init);
module_exit(cqcam_cleanup);
diff --git a/drivers/char/console.c b/drivers/char/console.c
index 4e69f8f4b..4b33e7433 100644
--- a/drivers/char/console.c
+++ b/drivers/char/console.c
@@ -2290,10 +2290,13 @@ static void con_start(struct tty_struct *tty)
static void con_flush_chars(struct tty_struct *tty)
{
+ unsigned long flags;
struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
pm_access(pm_con);
+ spin_lock_irqsave(&console_lock, flags);
set_cursor(vt->vc_num);
+ spin_unlock_irqrestore(&console_lock, flags);
}
/*
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 48047a637..cf4bb1f83 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1,7 +1,8 @@
#undef BLOCKMOVE
#define Z_WAKE
+#undef Z_EXT_CHARS_IN_BUFFER
static char rcsid[] =
-"$Revision: 2.3.2.6 $$Date: 2000/05/05 13:56:05 $";
+"$Revision: 2.3.2.7 $$Date: 2000/06/01 18:26:34 $";
/*
* linux/drivers/char/cyclades.c
@@ -24,6 +25,12 @@ static char rcsid[] =
* This version supports shared IRQ's (only for PCI boards).
*
* $Log: cyclades.c,v $
+ * Revision 2.3.2.7 2000/06/01 18:26:34 ivan
+ * Request PLX I/O region, although driver doesn't use it, to avoid
+ * problems with other drivers accessing it.
+ * Removed count for on-board buffer characters in cy_chars_in_buffer
+ * (Cyclades-Z only).
+ *
* Revision 2.3.2.6 2000/05/05 13:56:05 ivan
* Driver now reports physical instead of virtual memory addresses.
* Masks were added to some Cyclades-Z read accesses.
@@ -636,6 +643,7 @@ static char rcsid[] =
#include <linux/ptrace.h>
#include <linux/cyclades.h>
#include <linux/mm.h>
+#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
@@ -882,9 +890,8 @@ static void cyz_poll(unsigned long);
static long cyz_polling_cycle = CZ_DEF_POLL;
static int cyz_timeron = 0;
-static struct timer_list
-cyz_timerlist = {
- NULL, NULL, 0, 0, cyz_poll
+static struct timer_list cyz_timerlist = {
+ function: cyz_poll
};
#else /* CONFIG_CYZ_INTR */
static void cyz_rx_restart(unsigned long);
@@ -3122,12 +3129,15 @@ cy_chars_in_buffer(struct tty_struct *tty)
card = info->card;
channel = (info->line) - (cy_card[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); /* */
#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;
@@ -3156,6 +3166,7 @@ cy_chars_in_buffer(struct tty_struct *tty)
#endif
return (info->xmit_cnt + char_count);
}
+#endif /* Z_EXT_CHARS_IN_BUFFER */
} /* cy_chars_in_buffer */
@@ -4856,7 +4867,7 @@ cy_detect_pci(void)
struct pci_dev *pdev = NULL;
unsigned char cyy_rev_id;
unsigned char cy_pci_irq = 0;
- uclong cy_pci_phys0, cy_pci_phys2;
+ uclong cy_pci_phys0, cy_pci_phys1, cy_pci_phys2;
uclong cy_pci_addr0, cy_pci_addr2;
unsigned short i,j,cy_pci_nchan, plx_ver;
unsigned short device_id,dev_index = 0;
@@ -4885,6 +4896,7 @@ cy_detect_pci(void)
/* read PCI configuration area */
cy_pci_irq = pdev->irq;
cy_pci_phys0 = pci_resource_start(pdev, 0);
+ cy_pci_phys1 = pci_resource_start(pdev, 1);
cy_pci_phys2 = pci_resource_start(pdev, 2);
pci_read_config_byte(pdev, PCI_REVISION_ID, &cyy_rev_id);
@@ -4907,6 +4919,11 @@ cy_detect_pci(void)
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. */
+ request_region(cy_pci_phys1, CyPCI_Yctl, "Cyclom-Y");
+
#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, ",
@@ -5054,6 +5071,12 @@ cy_detect_pci(void)
"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. */
+ request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z");
+
if (mailbox == ZE_V1) {
#if !defined(__alpha__)
cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win);
diff --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c
index f663790db..8d8766b85 100644
--- a/drivers/char/dn_keyb.c
+++ b/drivers/char/dn_keyb.c
@@ -357,17 +357,14 @@ static void dn_keyb_process_mouse_event(unsigned char mouse_data) {
mouse_dy+=mouse_packet[2] == 0xff ? 0 : (signed char)mouse_packet[2];
wake_up_interruptible(&mouse_wait);
if (mouse_dx < -2048)
- mouse_dx = -2048;
- else
- if (mouse_dx > 2048)
- mouse_dx = 2048;
- if (mouse_dy < -2048)
- mouse_dy = -2048;
- else
- if (mouse_dy > 2048)
- mouse_dy = 2048;
- if (mouse_fasyncptr)
- kill_fasync(mouse_fasyncptr, SIGIO, POLL_IN);
+ mouse_dx = -2048;
+ else if (mouse_dx > 2048)
+ mouse_dx = 2048;
+ if (mouse_dy < -2048)
+ mouse_dy = -2048;
+ else if (mouse_dy > 2048)
+ mouse_dy = 2048;
+ kill_fasync(&mouse_fasyncptr, SIGIO, POLL_IN);
}
mouse_byte_count=0;
/* printk("mouse: %d, %d, %x\n",mouse_x,mouse_y,buttons); */
@@ -450,20 +447,8 @@ void write_keyb_cmd(u_short length, u_char *cmd) {
}
-static int release_mouse(struct inode * inode, struct file * file)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-static int open_mouse(struct inode * inode, struct file * file)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
static struct busmouse apollo_mouse = {
- APOLLO_MOUSE_MINOR, "apollomouse", open_mouse, release_mouse,7
+ APOLLO_MOUSE_MINOR, "apollomouse", THIS_MODULE, NULL, NULL, 7
};
int __init dn_keyb_init(void){
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
index ff70792d7..1c68f0cd2 100644
--- a/drivers/char/drm/Makefile
+++ b/drivers/char/drm/Makefile
@@ -39,6 +39,17 @@ else
endif
endif
+ifeq ($(CONFIG_DRM_FFB),y)
+ OX_OBJS += ffb_drv.o
+ O_OBJS += ffb_context.o
+else
+ ifeq ($(CONFIG_DRM_FFB),m)
+ MIX_OBJC += ffb_drv.o
+ MI_OBJS += ffb_context.o
+ M_OBJS += ffb.o
+ endif
+endif
+
O_OBJS += $(L_OBJS)
include $(TOPDIR)/Rules.make
@@ -48,3 +59,6 @@ gamma.o : gamma_drv.o gamma_dma.o $(L_OBJS)
tdfx.o: tdfx_drv.o tdfx_context.o $(L_OBJS)
$(LD) $(LD_RFLAG) -r -o $@ tdfx_drv.o tdfx_context.o $(L_OBJS)
+
+ffb.o: ffb_drv.o ffb_context.o $(L_OBJS)
+ $(LD) $(LD_RFLAG) -r -o $@ ffb_drv.o ffb_context.o $(L_OBJS)
diff --git a/drivers/char/drm/bufs.c b/drivers/char/drm/bufs.c
index 4e8c50c59..3d4c40222 100644
--- a/drivers/char/drm/bufs.c
+++ b/drivers/char/drm/bufs.c
@@ -72,11 +72,13 @@ int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd,
switch (map->type) {
case _DRM_REGISTERS:
case _DRM_FRAME_BUFFER:
+#ifndef __sparc__
if (map->offset + map->size < map->offset
|| map->offset < virt_to_phys(high_memory)) {
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
return -EINVAL;
}
+#endif
#ifdef CONFIG_MTRR
if (map->type == _DRM_FRAME_BUFFER
|| (map->flags & _DRM_WRITE_COMBINING)) {
@@ -478,8 +480,10 @@ int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
-EFAULT);
if (request.count >= dma->buf_count) {
+ down(&current->mm->mmap_sem);
virtual = do_mmap(filp, 0, dma->byte_count,
PROT_READ|PROT_WRITE, MAP_SHARED, 0);
+ up(&current->mm->mmap_sem);
if (virtual > -1024UL) {
/* Real error */
retcode = (signed long)virtual;
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 4d003ba2c..b39fec3f7 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -433,9 +433,9 @@ typedef struct drm_device {
/* Context support */
int irq; /* Interrupt used by board */
- __volatile__ int context_flag; /* Context swapping flag */
- __volatile__ int interrupt_flag;/* Interruption handler flag */
- __volatile__ int dma_flag; /* DMA dispatch flag */
+ __volatile__ long context_flag; /* Context swapping flag */
+ __volatile__ long interrupt_flag;/* Interruption handler flag */
+ __volatile__ long dma_flag; /* DMA dispatch flag */
struct timer_list timer; /* Timer for delaying ctx switch */
wait_queue_head_t context_wait; /* Processes waiting on ctx switch */
int last_checked; /* Last context checked for DMA */
diff --git a/drivers/char/drm/ffb_context.c b/drivers/char/drm/ffb_context.c
new file mode 100644
index 000000000..a10b59898
--- /dev/null
+++ b/drivers/char/drm/ffb_context.c
@@ -0,0 +1,530 @@
+/* $Id: ffb_context.c,v 1.3 2000/06/09 03:46:53 davem Exp $
+ * ffb_context.c: Creator/Creator3D DRI/DRM context switching.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ *
+ * Almost entirely stolen from tdfx_context.c, see there
+ * for authors.
+ */
+
+#include <linux/sched.h>
+#include <asm/upa.h>
+
+#include "drmP.h"
+
+#include "ffb_drv.h"
+
+static int ffb_alloc_queue(drm_device_t *dev, int is_2d_only)
+{
+ ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+ int i;
+
+ for (i = 0; i < FFB_MAX_CTXS; i++) {
+ if (fpriv->hw_state[i] == NULL)
+ break;
+ }
+ if (i == FFB_MAX_CTXS)
+ return -1;
+
+ fpriv->hw_state[i] = kmalloc(sizeof(struct ffb_hw_context), GFP_KERNEL);
+ if (fpriv->hw_state[i] == NULL)
+ return -1;
+
+ fpriv->hw_state[i]->is_2d_only = is_2d_only;
+
+ /* Plus one because 0 is the special DRM_KERNEL_CONTEXT. */
+ return i + 1;
+}
+
+static void ffb_save_context(ffb_dev_priv_t *fpriv, int idx)
+{
+ ffb_fbcPtr ffb = fpriv->regs;
+ struct ffb_hw_context *ctx;
+ int i;
+
+ ctx = fpriv->hw_state[idx - 1];
+ if (idx == 0 || ctx == NULL)
+ return;
+
+ if (ctx->is_2d_only) {
+ /* 2D applications only care about certain pieces
+ * of state.
+ */
+ ctx->drawop = upa_readl(&ffb->drawop);
+ ctx->ppc = upa_readl(&ffb->ppc);
+ ctx->wid = upa_readl(&ffb->wid);
+ ctx->fg = upa_readl(&ffb->fg);
+ ctx->bg = upa_readl(&ffb->bg);
+ ctx->xclip = upa_readl(&ffb->xclip);
+ ctx->fbc = upa_readl(&ffb->fbc);
+ ctx->rop = upa_readl(&ffb->rop);
+ ctx->cmp = upa_readl(&ffb->cmp);
+ ctx->matchab = upa_readl(&ffb->matchab);
+ ctx->magnab = upa_readl(&ffb->magnab);
+ ctx->pmask = upa_readl(&ffb->pmask);
+ ctx->xpmask = upa_readl(&ffb->xpmask);
+ ctx->lpat = upa_readl(&ffb->lpat);
+ ctx->fontxy = upa_readl(&ffb->fontxy);
+ ctx->fontw = upa_readl(&ffb->fontw);
+ ctx->fontinc = upa_readl(&ffb->fontinc);
+
+ /* stencil/stencilctl only exists on FFB2+ and later
+ * due to the introduction of 3DRAM-III.
+ */
+ if (fpriv->ffb_type == ffb2_vertical_plus ||
+ fpriv->ffb_type == ffb2_horizontal_plus) {
+ ctx->stencil = upa_readl(&ffb->stencil);
+ ctx->stencilctl = upa_readl(&ffb->stencilctl);
+ }
+
+ for (i = 0; i < 32; i++)
+ ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]);
+ ctx->ucsr = upa_readl(&ffb->ucsr);
+ return;
+ }
+
+ /* Fetch drawop. */
+ ctx->drawop = upa_readl(&ffb->drawop);
+
+ /* If we were saving the vertex registers, this is where
+ * we would do it. We would save 32 32-bit words starting
+ * at ffb->suvtx.
+ */
+
+ /* Capture rendering attributes. */
+
+ ctx->ppc = upa_readl(&ffb->ppc); /* Pixel Processor Control */
+ ctx->wid = upa_readl(&ffb->wid); /* Current WID */
+ ctx->fg = upa_readl(&ffb->fg); /* Constant FG color */
+ ctx->bg = upa_readl(&ffb->bg); /* Constant BG color */
+ ctx->consty = upa_readl(&ffb->consty); /* Constant Y */
+ ctx->constz = upa_readl(&ffb->constz); /* Constant Z */
+ ctx->xclip = upa_readl(&ffb->xclip); /* X plane clip */
+ ctx->dcss = upa_readl(&ffb->dcss); /* Depth Cue Scale Slope */
+ ctx->vclipmin = upa_readl(&ffb->vclipmin); /* Primary XY clip, minimum */
+ ctx->vclipmax = upa_readl(&ffb->vclipmax); /* Primary XY clip, maximum */
+ ctx->vclipzmin = upa_readl(&ffb->vclipzmin); /* Primary Z clip, minimum */
+ ctx->vclipzmax = upa_readl(&ffb->vclipzmax); /* Primary Z clip, maximum */
+ ctx->dcsf = upa_readl(&ffb->dcsf); /* Depth Cue Scale Front Bound */
+ ctx->dcsb = upa_readl(&ffb->dcsb); /* Depth Cue Scale Back Bound */
+ ctx->dczf = upa_readl(&ffb->dczf); /* Depth Cue Scale Z Front */
+ ctx->dczb = upa_readl(&ffb->dczb); /* Depth Cue Scale Z Back */
+ ctx->blendc = upa_readl(&ffb->blendc); /* Alpha Blend Control */
+ ctx->blendc1 = upa_readl(&ffb->blendc1); /* Alpha Blend Color 1 */
+ ctx->blendc2 = upa_readl(&ffb->blendc2); /* Alpha Blend Color 2 */
+ ctx->fbc = upa_readl(&ffb->fbc); /* Frame Buffer Control */
+ ctx->rop = upa_readl(&ffb->rop); /* Raster Operation */
+ ctx->cmp = upa_readl(&ffb->cmp); /* Compare Controls */
+ ctx->matchab = upa_readl(&ffb->matchab); /* Buffer A/B Match Ops */
+ ctx->matchc = upa_readl(&ffb->matchc); /* Buffer C Match Ops */
+ ctx->magnab = upa_readl(&ffb->magnab); /* Buffer A/B Magnitude Ops */
+ ctx->magnc = upa_readl(&ffb->magnc); /* Buffer C Magnitude Ops */
+ ctx->pmask = upa_readl(&ffb->pmask); /* RGB Plane Mask */
+ ctx->xpmask = upa_readl(&ffb->xpmask); /* X Plane Mask */
+ ctx->ypmask = upa_readl(&ffb->ypmask); /* Y Plane Mask */
+ ctx->zpmask = upa_readl(&ffb->zpmask); /* Z Plane Mask */
+
+ /* Auxiliary Clips. */
+ ctx->auxclip0min = upa_readl(&ffb->auxclip[0].min);
+ ctx->auxclip0max = upa_readl(&ffb->auxclip[0].max);
+ ctx->auxclip1min = upa_readl(&ffb->auxclip[1].min);
+ ctx->auxclip1max = upa_readl(&ffb->auxclip[1].max);
+ ctx->auxclip2min = upa_readl(&ffb->auxclip[2].min);
+ ctx->auxclip2max = upa_readl(&ffb->auxclip[2].max);
+ ctx->auxclip3min = upa_readl(&ffb->auxclip[3].min);
+ ctx->auxclip3max = upa_readl(&ffb->auxclip[3].max);
+
+ ctx->lpat = upa_readl(&ffb->lpat); /* Line Pattern */
+ ctx->fontxy = upa_readl(&ffb->fontxy); /* XY Font Coordinate */
+ ctx->fontw = upa_readl(&ffb->fontw); /* Font Width */
+ ctx->fontinc = upa_readl(&ffb->fontinc); /* Font X/Y Increment */
+
+ /* These registers/features only exist on FFB2 and later chips. */
+ if (fpriv->ffb_type >= ffb2_prototype) {
+ ctx->dcss1 = upa_readl(&ffb->dcss1); /* Depth Cue Scale Slope 1 */
+ ctx->dcss2 = upa_readl(&ffb->dcss2); /* Depth Cue Scale Slope 2 */
+ ctx->dcss2 = upa_readl(&ffb->dcss3); /* Depth Cue Scale Slope 3 */
+ ctx->dcs2 = upa_readl(&ffb->dcs2); /* Depth Cue Scale 2 */
+ ctx->dcs3 = upa_readl(&ffb->dcs3); /* Depth Cue Scale 3 */
+ ctx->dcs4 = upa_readl(&ffb->dcs4); /* Depth Cue Scale 4 */
+ ctx->dcd2 = upa_readl(&ffb->dcd2); /* Depth Cue Depth 2 */
+ ctx->dcd3 = upa_readl(&ffb->dcd3); /* Depth Cue Depth 3 */
+ ctx->dcd4 = upa_readl(&ffb->dcd4); /* Depth Cue Depth 4 */
+
+ /* And stencil/stencilctl only exists on FFB2+ and later
+ * due to the introduction of 3DRAM-III.
+ */
+ if (fpriv->ffb_type == ffb2_vertical_plus ||
+ fpriv->ffb_type == ffb2_horizontal_plus) {
+ ctx->stencil = upa_readl(&ffb->stencil);
+ ctx->stencilctl = upa_readl(&ffb->stencilctl);
+ }
+ }
+
+ /* Save the 32x32 area pattern. */
+ for (i = 0; i < 32; i++)
+ ctx->area_pattern[i] = upa_readl(&ffb->pattern[i]);
+
+ /* Finally, stash away the User Constol/Status Register. */
+ ctx->ucsr = upa_readl(&ffb->ucsr);
+}
+
+static void ffb_restore_context(ffb_dev_priv_t *fpriv, int old, int idx)
+{
+ ffb_fbcPtr ffb = fpriv->regs;
+ struct ffb_hw_context *ctx;
+ int i;
+
+ ctx = fpriv->hw_state[idx - 1];
+ if (idx == 0 || ctx == NULL)
+ return;
+
+ if (ctx->is_2d_only) {
+ /* 2D applications only care about certain pieces
+ * of state.
+ */
+ upa_writel(ctx->drawop, &ffb->drawop);
+
+ /* If we were restoring the vertex registers, this is where
+ * we would do it. We would restore 32 32-bit words starting
+ * at ffb->suvtx.
+ */
+
+ upa_writel(ctx->ppc, &ffb->ppc);
+ upa_writel(ctx->wid, &ffb->wid);
+ upa_writel(ctx->fg, &ffb->fg);
+ upa_writel(ctx->bg, &ffb->bg);
+ upa_writel(ctx->xclip, &ffb->xclip);
+ upa_writel(ctx->fbc, &ffb->fbc);
+ upa_writel(ctx->rop, &ffb->rop);
+ upa_writel(ctx->cmp, &ffb->cmp);
+ upa_writel(ctx->matchab, &ffb->matchab);
+ upa_writel(ctx->magnab, &ffb->magnab);
+ upa_writel(ctx->pmask, &ffb->pmask);
+ upa_writel(ctx->xpmask, &ffb->xpmask);
+ upa_writel(ctx->lpat, &ffb->lpat);
+ upa_writel(ctx->fontxy, &ffb->fontxy);
+ upa_writel(ctx->fontw, &ffb->fontw);
+ upa_writel(ctx->fontinc, &ffb->fontinc);
+
+ /* stencil/stencilctl only exists on FFB2+ and later
+ * due to the introduction of 3DRAM-III.
+ */
+ if (fpriv->ffb_type == ffb2_vertical_plus ||
+ fpriv->ffb_type == ffb2_horizontal_plus) {
+ upa_writel(ctx->stencil, &ffb->stencil);
+ upa_writel(ctx->stencilctl, &ffb->stencilctl);
+ upa_writel(0x80000000, &ffb->fbc);
+ upa_writel((ctx->stencilctl | 0x80000),
+ &ffb->rawstencilctl);
+ upa_writel(ctx->fbc, &ffb->fbc);
+ }
+
+ for (i = 0; i < 32; i++)
+ upa_writel(ctx->area_pattern[i], &ffb->pattern[i]);
+ upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr);
+ return;
+ }
+
+ /* Restore drawop. */
+ upa_writel(ctx->drawop, &ffb->drawop);
+
+ /* If we were restoring the vertex registers, this is where
+ * we would do it. We would restore 32 32-bit words starting
+ * at ffb->suvtx.
+ */
+
+ /* Restore rendering attributes. */
+
+ upa_writel(ctx->ppc, &ffb->ppc); /* Pixel Processor Control */
+ upa_writel(ctx->wid, &ffb->wid); /* Current WID */
+ upa_writel(ctx->fg, &ffb->fg); /* Constant FG color */
+ upa_writel(ctx->bg, &ffb->bg); /* Constant BG color */
+ upa_writel(ctx->consty, &ffb->consty); /* Constant Y */
+ upa_writel(ctx->constz, &ffb->constz); /* Constant Z */
+ upa_writel(ctx->xclip, &ffb->xclip); /* X plane clip */
+ upa_writel(ctx->dcss, &ffb->dcss); /* Depth Cue Scale Slope */
+ upa_writel(ctx->vclipmin, &ffb->vclipmin); /* Primary XY clip, minimum */
+ upa_writel(ctx->vclipmax, &ffb->vclipmax); /* Primary XY clip, maximum */
+ upa_writel(ctx->vclipzmin, &ffb->vclipzmin); /* Primary Z clip, minimum */
+ upa_writel(ctx->vclipzmax, &ffb->vclipzmax); /* Primary Z clip, maximum */
+ upa_writel(ctx->dcsf, &ffb->dcsf); /* Depth Cue Scale Front Bound */
+ upa_writel(ctx->dcsb, &ffb->dcsb); /* Depth Cue Scale Back Bound */
+ upa_writel(ctx->dczf, &ffb->dczf); /* Depth Cue Scale Z Front */
+ upa_writel(ctx->dczb, &ffb->dczb); /* Depth Cue Scale Z Back */
+ upa_writel(ctx->blendc, &ffb->blendc); /* Alpha Blend Control */
+ upa_writel(ctx->blendc1, &ffb->blendc1); /* Alpha Blend Color 1 */
+ upa_writel(ctx->blendc2, &ffb->blendc2); /* Alpha Blend Color 2 */
+ upa_writel(ctx->fbc, &ffb->fbc); /* Frame Buffer Control */
+ upa_writel(ctx->rop, &ffb->rop); /* Raster Operation */
+ upa_writel(ctx->cmp, &ffb->cmp); /* Compare Controls */
+ upa_writel(ctx->matchab, &ffb->matchab); /* Buffer A/B Match Ops */
+ upa_writel(ctx->matchc, &ffb->matchc); /* Buffer C Match Ops */
+ upa_writel(ctx->magnab, &ffb->magnab); /* Buffer A/B Magnitude Ops */
+ upa_writel(ctx->magnc, &ffb->magnc); /* Buffer C Magnitude Ops */
+ upa_writel(ctx->pmask, &ffb->pmask); /* RGB Plane Mask */
+ upa_writel(ctx->xpmask, &ffb->xpmask); /* X Plane Mask */
+ upa_writel(ctx->ypmask, &ffb->ypmask); /* Y Plane Mask */
+ upa_writel(ctx->zpmask, &ffb->zpmask); /* Z Plane Mask */
+
+ /* Auxiliary Clips. */
+ upa_writel(ctx->auxclip0min, &ffb->auxclip[0].min);
+ upa_writel(ctx->auxclip0max, &ffb->auxclip[0].max);
+ upa_writel(ctx->auxclip1min, &ffb->auxclip[1].min);
+ upa_writel(ctx->auxclip1max, &ffb->auxclip[1].max);
+ upa_writel(ctx->auxclip2min, &ffb->auxclip[2].min);
+ upa_writel(ctx->auxclip2max, &ffb->auxclip[2].max);
+ upa_writel(ctx->auxclip3min, &ffb->auxclip[3].min);
+ upa_writel(ctx->auxclip3max, &ffb->auxclip[3].max);
+
+ upa_writel(ctx->lpat, &ffb->lpat); /* Line Pattern */
+ upa_writel(ctx->fontxy, &ffb->fontxy); /* XY Font Coordinate */
+ upa_writel(ctx->fontw, &ffb->fontw); /* Font Width */
+ upa_writel(ctx->fontinc, &ffb->fontinc); /* Font X/Y Increment */
+
+ /* These registers/features only exist on FFB2 and later chips. */
+ if (fpriv->ffb_type >= ffb2_prototype) {
+ upa_writel(ctx->dcss1, &ffb->dcss1); /* Depth Cue Scale Slope 1 */
+ upa_writel(ctx->dcss2, &ffb->dcss2); /* Depth Cue Scale Slope 2 */
+ upa_writel(ctx->dcss3, &ffb->dcss2); /* Depth Cue Scale Slope 3 */
+ upa_writel(ctx->dcs2, &ffb->dcs2); /* Depth Cue Scale 2 */
+ upa_writel(ctx->dcs3, &ffb->dcs3); /* Depth Cue Scale 3 */
+ upa_writel(ctx->dcs4, &ffb->dcs4); /* Depth Cue Scale 4 */
+ upa_writel(ctx->dcd2, &ffb->dcd2); /* Depth Cue Depth 2 */
+ upa_writel(ctx->dcd3, &ffb->dcd3); /* Depth Cue Depth 3 */
+ upa_writel(ctx->dcd4, &ffb->dcd4); /* Depth Cue Depth 4 */
+
+ /* And stencil/stencilctl only exists on FFB2+ and later
+ * due to the introduction of 3DRAM-III.
+ */
+ if (fpriv->ffb_type == ffb2_vertical_plus ||
+ fpriv->ffb_type == ffb2_horizontal_plus) {
+ /* Unfortunately, there is a hardware bug on
+ * the FFB2+ chips which prevents a normal write
+ * to the stencil control register from working
+ * as it should.
+ *
+ * The state controlled by the FFB stencilctl register
+ * really gets transferred to the per-buffer instances
+ * of the stencilctl register in the 3DRAM chips.
+ *
+ * The bug is that FFB does not update buffer C correctly,
+ * so we have to do it by hand for them.
+ */
+
+ /* This will update buffers A and B. */
+ upa_writel(ctx->stencil, &ffb->stencil);
+ upa_writel(ctx->stencilctl, &ffb->stencilctl);
+
+ /* Force FFB to use buffer C 3dram regs. */
+ upa_writel(0x80000000, &ffb->fbc);
+ upa_writel((ctx->stencilctl | 0x80000),
+ &ffb->rawstencilctl);
+
+ /* Now restore the correct FBC controls. */
+ upa_writel(ctx->fbc, &ffb->fbc);
+ }
+ }
+
+ /* Restore the 32x32 area pattern. */
+ for (i = 0; i < 32; i++)
+ upa_writel(ctx->area_pattern[i], &ffb->pattern[i]);
+
+ /* Finally, stash away the User Constol/Status Register.
+ * The only state we really preserve here is the picking
+ * control.
+ */
+ upa_writel((ctx->ucsr & 0xf0000), &ffb->ucsr);
+}
+
+#define FFB_UCSR_FB_BUSY 0x01000000
+#define FFB_UCSR_RP_BUSY 0x02000000
+#define FFB_UCSR_ALL_BUSY (FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
+
+static void FFBWait(ffb_fbcPtr ffb)
+{
+ int limit = 100000;
+
+ do {
+ u32 regval = upa_readl(&ffb->ucsr);
+
+ if ((regval & FFB_UCSR_ALL_BUSY) == 0)
+ break;
+ } while (--limit);
+}
+
+int ffb_context_switch(drm_device_t *dev, int old, int new)
+{
+ ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+
+ atomic_inc(&dev->total_ctx);
+
+#if DRM_DMA_HISTOGRAM
+ dev->ctx_start = get_cycles();
+#endif
+
+ DRM_DEBUG("Context switch from %d to %d\n", old, new);
+
+ if (new == dev->last_context ||
+ dev->last_context == 0) {
+ dev->last_context = new;
+ return 0;
+ }
+
+ FFBWait(fpriv->regs);
+ ffb_save_context(fpriv, old);
+ ffb_restore_context(fpriv, old, new);
+ FFBWait(fpriv->regs);
+
+ dev->last_context = new;
+
+ return 0;
+}
+
+int ffb_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_ctx_res_t res;
+ drm_ctx_t ctx;
+ int i;
+
+ DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
+ copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+ if (res.count >= DRM_RESERVED_CONTEXTS) {
+ memset(&ctx, 0, sizeof(ctx));
+ for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
+ ctx.handle = i;
+ copy_to_user_ret(&res.contexts[i],
+ &i,
+ sizeof(i),
+ -EFAULT);
+ }
+ }
+ res.count = DRM_RESERVED_CONTEXTS;
+ copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+ return 0;
+}
+
+
+int ffb_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+ int idx;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ idx = ffb_alloc_queue(dev, (ctx.flags & _DRM_CONTEXT_2DONLY));
+ if (idx < 0)
+ return -ENFILE;
+
+ DRM_DEBUG("%d\n", ctx.handle);
+ ctx.handle = idx;
+ copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+ return 0;
+}
+
+int ffb_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+ struct ffb_hw_context *hwctx;
+ drm_ctx_t ctx;
+ int idx;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+
+ idx = ctx.handle;
+ if (idx <= 0 || idx >= FFB_MAX_CTXS)
+ return -EINVAL;
+
+ hwctx = fpriv->hw_state[idx - 1];
+ if (hwctx == NULL)
+ return -EINVAL;
+
+ if ((ctx.flags & _DRM_CONTEXT_2DONLY) == 0)
+ hwctx->is_2d_only = 0;
+ else
+ hwctx->is_2d_only = 1;
+
+ return 0;
+}
+
+int ffb_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+ struct ffb_hw_context *hwctx;
+ drm_ctx_t ctx;
+ int idx;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+
+ idx = ctx.handle;
+ if (idx <= 0 || idx >= FFB_MAX_CTXS)
+ return -EINVAL;
+
+ hwctx = fpriv->hw_state[idx - 1];
+ if (hwctx == NULL)
+ return -EINVAL;
+
+ if (hwctx->is_2d_only != 0)
+ ctx.flags = _DRM_CONTEXT_2DONLY;
+ else
+ ctx.flags = 0;
+
+ copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+
+ return 0;
+}
+
+int ffb_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ctx_t ctx;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ DRM_DEBUG("%d\n", ctx.handle);
+ return ffb_context_switch(dev, dev->last_context, ctx.handle);
+}
+
+int ffb_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_ctx_t ctx;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ DRM_DEBUG("%d\n", ctx.handle);
+
+ return 0;
+}
+
+int ffb_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_ctx_t ctx;
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+ int idx;
+
+ copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ DRM_DEBUG("%d\n", ctx.handle);
+
+ idx = ctx.handle - 1;
+ if (idx < 0 || idx >= FFB_MAX_CTXS)
+ return -EINVAL;
+
+ if (fpriv->hw_state[idx] != NULL) {
+ kfree(fpriv->hw_state[idx]);
+ fpriv->hw_state[idx] = NULL;
+ }
+ return 0;
+}
diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c
new file mode 100644
index 000000000..a1ab1f279
--- /dev/null
+++ b/drivers/char/drm/ffb_drv.c
@@ -0,0 +1,842 @@
+/* $Id: ffb_drv.c,v 1.3 2000/06/01 04:24:39 davem Exp $
+ * ffb_drv.c: Creator/Creator3D direct rendering driver.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ */
+
+#include "drmP.h"
+
+#include <asm/oplib.h>
+#include <asm/upa.h>
+
+#include "ffb_drv.h"
+
+#define FFB_NAME "ffb"
+#define FFB_DESC "Creator/Creator3D"
+#define FFB_DATE "20000517"
+#define FFB_MAJOR 0
+#define FFB_MINOR 0
+#define FFB_PATCHLEVEL 1
+
+/* Forward declarations. */
+int ffb_init(void);
+void ffb_cleanup(void);
+static int ffb_version(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+static int ffb_open(struct inode *inode, struct file *filp);
+static int ffb_release(struct inode *inode, struct file *filp);
+static int ffb_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+static int ffb_lock(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+static int ffb_unlock(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+static int ffb_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/* From ffb_context.c */
+extern int ffb_resctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_addctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_modctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_getctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_switchctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_newctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_rmctx(struct inode *, struct file *, unsigned int, unsigned long);
+extern int ffb_context_switch(drm_device_t *, int, int);
+
+static struct file_operations ffb_fops = {
+ open: ffb_open,
+ flush: drm_flush,
+ release: ffb_release,
+ ioctl: ffb_ioctl,
+ mmap: ffb_mmap,
+ read: drm_read,
+ fasync: drm_fasync,
+ poll: drm_poll,
+};
+
+/* This is just a template, we make a new copy for each FFB
+ * we discover at init time so that each one gets a unique
+ * misc device minor number.
+ */
+static struct miscdevice ffb_misc = {
+ minor: MISC_DYNAMIC_MINOR,
+ name: FFB_NAME,
+ fops: &ffb_fops,
+};
+
+static drm_ioctl_desc_t ffb_ioctls[] = {
+ [DRM_IOCTL_NR(DRM_IOCTL_VERSION)] = { ffb_version, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE)] = { drm_getunique, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_MAGIC)] = { drm_getmagic, 0, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_IRQ_BUSID)] = { drm_irq_busid, 0, 1 }, /* XXX */
+
+ [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE)] = { drm_setunique, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_BLOCK)] = { drm_block, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_UNBLOCK)] = { drm_unblock, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_AUTH_MAGIC)] = { drm_authmagic, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP)] = { drm_addmap, 1, 1 },
+
+ /* The implementation is currently a nop just like on tdfx.
+ * Later we can do something more clever. -DaveM
+ */
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { ffb_addctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { ffb_rmctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { ffb_modctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_CTX)] = { ffb_getctx, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_SWITCH_CTX)] = { ffb_switchctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_NEW_CTX)] = { ffb_newctx, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX)] = { ffb_resctx, 1, 0 },
+
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_DRAW)] = { drm_adddraw, 1, 1 },
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_DRAW)] = { drm_rmdraw, 1, 1 },
+
+ [DRM_IOCTL_NR(DRM_IOCTL_LOCK)] = { ffb_lock, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_UNLOCK)] = { ffb_unlock, 1, 0 },
+ [DRM_IOCTL_NR(DRM_IOCTL_FINISH)] = { drm_finish, 1, 0 },
+};
+#define FFB_IOCTL_COUNT DRM_ARRAY_SIZE(ffb_ioctls)
+
+#ifdef MODULE
+static char *ffb = NULL;
+#endif
+
+MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_DESCRIPTION("Sun Creator/Creator3D DRI");
+
+static int ffb_takedown(drm_device_t *dev)
+{
+ int i;
+ drm_magic_entry_t *pt, *next;
+ drm_map_t *map;
+ drm_vma_entry_t *vma, *vma_next;
+
+ DRM_DEBUG("\n");
+
+ down(&dev->struct_sem);
+ del_timer(&dev->timer);
+
+ if (dev->devname) {
+ drm_free(dev->devname, strlen(dev->devname)+1, DRM_MEM_DRIVER);
+ dev->devname = NULL;
+ }
+
+ if (dev->unique) {
+ drm_free(dev->unique, strlen(dev->unique)+1, DRM_MEM_DRIVER);
+ dev->unique = NULL;
+ dev->unique_len = 0;
+ }
+
+ /* Clear pid list */
+ for (i = 0; i < DRM_HASH_SIZE; i++) {
+ for (pt = dev->magiclist[i].head; pt; pt = next) {
+ next = pt->next;
+ drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
+ }
+ dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+ }
+
+ /* Clear vma list (only built for debugging) */
+ if (dev->vmalist) {
+ for (vma = dev->vmalist; vma; vma = vma_next) {
+ vma_next = vma->next;
+ drm_free(vma, sizeof(*vma), DRM_MEM_VMAS);
+ }
+ dev->vmalist = NULL;
+ }
+
+ /* Clear map area information */
+ if (dev->maplist) {
+ for (i = 0; i < dev->map_count; i++) {
+ map = dev->maplist[i];
+ switch (map->type) {
+ case _DRM_REGISTERS:
+ case _DRM_FRAME_BUFFER:
+ drm_ioremapfree(map->handle, map->size);
+ break;
+
+ case _DRM_SHM:
+ drm_free_pages((unsigned long)map->handle,
+ drm_order(map->size)
+ - PAGE_SHIFT,
+ DRM_MEM_SAREA);
+ break;
+ };
+
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ }
+
+ drm_free(dev->maplist,
+ dev->map_count * sizeof(*dev->maplist),
+ DRM_MEM_MAPS);
+ dev->maplist = NULL;
+ dev->map_count = 0;
+ }
+
+ if (dev->lock.hw_lock) {
+ dev->lock.hw_lock = NULL; /* SHM removed */
+ dev->lock.pid = 0;
+ wake_up_interruptible(&dev->lock.lock_queue);
+ }
+ up(&dev->struct_sem);
+
+ return 0;
+}
+
+drm_device_t **ffb_dev_table;
+static int ffb_dev_table_size;
+
+static void get_ffb_type(ffb_dev_priv_t *ffb_priv, int instance)
+{
+ volatile unsigned char *strap_bits;
+ unsigned char val;
+
+ strap_bits = (volatile unsigned char *)
+ (ffb_priv->card_phys_base + 0x00200000UL);
+
+ /* Don't ask, you have to read the value twice for whatever
+ * reason to get correct contents.
+ */
+ val = upa_readb(strap_bits);
+ val = upa_readb(strap_bits);
+ switch (val & 0x78) {
+ case (0x0 << 5) | (0x0 << 3):
+ ffb_priv->ffb_type = ffb1_prototype;
+ printk("ffb%d: Detected FFB1 pre-FCS prototype\n", instance);
+ break;
+ case (0x0 << 5) | (0x1 << 3):
+ ffb_priv->ffb_type = ffb1_standard;
+ printk("ffb%d: Detected FFB1\n", instance);
+ break;
+ case (0x0 << 5) | (0x3 << 3):
+ ffb_priv->ffb_type = ffb1_speedsort;
+ printk("ffb%d: Detected FFB1-SpeedSort\n", instance);
+ break;
+ case (0x1 << 5) | (0x0 << 3):
+ ffb_priv->ffb_type = ffb2_prototype;
+ printk("ffb%d: Detected FFB2/vertical pre-FCS prototype\n", instance);
+ break;
+ case (0x1 << 5) | (0x1 << 3):
+ ffb_priv->ffb_type = ffb2_vertical;
+ printk("ffb%d: Detected FFB2/vertical\n", instance);
+ break;
+ case (0x1 << 5) | (0x2 << 3):
+ ffb_priv->ffb_type = ffb2_vertical_plus;
+ printk("ffb%d: Detected FFB2+/vertical\n", instance);
+ break;
+ case (0x2 << 5) | (0x0 << 3):
+ ffb_priv->ffb_type = ffb2_horizontal;
+ printk("ffb%d: Detected FFB2/horizontal\n", instance);
+ break;
+ case (0x2 << 5) | (0x2 << 3):
+ ffb_priv->ffb_type = ffb2_horizontal;
+ printk("ffb%d: Detected FFB2+/horizontal\n", instance);
+ break;
+ default:
+ ffb_priv->ffb_type = ffb2_vertical;
+ printk("ffb%d: Unknown boardID[%08x], assuming FFB2\n", instance, val);
+ break;
+ };
+}
+
+static int ffb_init_one(int prom_node, int instance)
+{
+ struct linux_prom64_registers regs[2*PROMREG_MAX];
+ drm_device_t *dev;
+ ffb_dev_priv_t *ffb_priv;
+ int ret, i;
+
+ dev = kmalloc(sizeof(drm_device_t) + sizeof(ffb_dev_priv_t), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ memset(dev, 0, sizeof(*dev));
+ spin_lock_init(&dev->count_lock);
+ sema_init(&dev->struct_sem, 1);
+
+ ffb_priv = (ffb_dev_priv_t *) (dev + 1);
+ ffb_priv->prom_node = prom_node;
+ if (prom_getproperty(ffb_priv->prom_node, "reg",
+ (void *)regs, sizeof(regs)) <= 0) {
+ kfree(dev);
+ return -EINVAL;
+ }
+ ffb_priv->card_phys_base = regs[0].phys_addr;
+ ffb_priv->regs = (ffb_fbcPtr)
+ (regs[0].phys_addr + 0x00600000UL);
+ get_ffb_type(ffb_priv, instance);
+ for (i = 0; i < FFB_MAX_CTXS; i++)
+ ffb_priv->hw_state[i] = NULL;
+
+ ffb_dev_table[instance] = dev;
+
+#ifdef MODULE
+ drm_parse_options(ffb);
+#endif
+
+ memcpy(&ffb_priv->miscdev, &ffb_misc, sizeof(ffb_misc));
+ ret = misc_register(&ffb_priv->miscdev);
+ if (ret) {
+ ffb_dev_table[instance] = NULL;
+ kfree(dev);
+ return ret;
+ }
+
+ dev->device = MKDEV(MISC_MAJOR, ffb_priv->miscdev.minor);
+ dev->name = FFB_NAME;
+
+ drm_mem_init();
+ drm_proc_init(dev);
+
+ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d at %016lx\n",
+ FFB_NAME,
+ FFB_MAJOR,
+ FFB_MINOR,
+ FFB_PATCHLEVEL,
+ FFB_DATE,
+ ffb_priv->miscdev.minor,
+ ffb_priv->card_phys_base);
+
+ return 0;
+}
+
+static int ffb_init_dev_table(void)
+{
+ int root, node;
+ int total = 0;
+
+ root = prom_getchild(prom_root_node);
+ for (node = prom_searchsiblings(root, "SUNW,ffb"); node;
+ node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
+ total++;
+
+ ffb_dev_table = kmalloc(sizeof(drm_device_t *) * total, GFP_KERNEL);
+ if (!ffb_dev_table)
+ return -ENOMEM;
+
+ ffb_dev_table_size = total;
+
+ return 0;
+}
+
+int ffb_init(void)
+{
+ int root, node, instance, ret;
+
+ ret = ffb_init_dev_table();
+ if (ret)
+ return ret;
+
+ instance = 0;
+ root = prom_getchild(prom_root_node);
+ for (node = prom_searchsiblings(root, "SUNW,ffb"); node;
+ node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb")) {
+ ret = ffb_init_one(node, instance);
+ if (ret)
+ return ret;
+ instance++;
+ }
+
+ return 0;
+}
+
+void ffb_cleanup(void)
+{
+ int instance;
+
+ DRM_DEBUG("\n");
+
+ drm_proc_cleanup();
+ for (instance = 0; instance < ffb_dev_table_size; instance++) {
+ drm_device_t *dev = ffb_dev_table[instance];
+ ffb_dev_priv_t *ffb_priv;
+
+ if (!dev)
+ continue;
+
+ ffb_priv = (ffb_dev_priv_t *) (dev + 1);
+ if (misc_deregister(&ffb_priv->miscdev)) {
+ DRM_ERROR("Cannot unload module\n");
+ } else {
+ DRM_INFO("Module unloaded\n");
+ }
+ ffb_takedown(dev);
+ kfree(dev);
+ ffb_dev_table[instance] = NULL;
+ }
+ kfree(ffb_dev_table);
+ ffb_dev_table = NULL;
+ ffb_dev_table_size = 0;
+}
+
+static int ffb_version(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ drm_version_t version;
+ int len, ret;
+
+ ret = copy_from_user(&version, (drm_version_t *)arg, sizeof(version));
+ if (ret)
+ return -EFAULT;
+
+ version.version_major = FFB_MAJOR;
+ version.version_minor = FFB_MINOR;
+ version.version_patchlevel = FFB_PATCHLEVEL;
+
+ len = strlen(FFB_NAME);
+ if (len > version.name_len)
+ len = version.name_len;
+ version.name_len = len;
+ if (len && version.name) {
+ ret = copy_to_user(version.name, FFB_NAME, len);
+ if (ret)
+ return -EFAULT;
+ }
+
+ len = strlen(FFB_DATE);
+ if (len > version.date_len)
+ len = version.date_len;
+ version.date_len = len;
+ if (len && version.date) {
+ ret = copy_to_user(version.date, FFB_DATE, len);
+ if (ret)
+ return -EFAULT;
+ }
+
+ len = strlen(FFB_DESC);
+ if (len > version.desc_len)
+ len = version.desc_len;
+ version.desc_len = len;
+ if (len && version.desc) {
+ ret = copy_to_user(version.desc, FFB_DESC, len);
+ if (ret)
+ return -EFAULT;
+ }
+
+ ret = copy_to_user((drm_version_t *) arg, &version, sizeof(version));
+ if (ret)
+ ret = -EFAULT;
+
+ return ret;
+}
+
+static int ffb_setup(drm_device_t *dev)
+{
+ int i;
+
+ atomic_set(&dev->ioctl_count, 0);
+ atomic_set(&dev->vma_count, 0);
+ dev->buf_use = 0;
+ atomic_set(&dev->buf_alloc, 0);
+
+ atomic_set(&dev->total_open, 0);
+ atomic_set(&dev->total_close, 0);
+ atomic_set(&dev->total_ioctl, 0);
+ atomic_set(&dev->total_irq, 0);
+ atomic_set(&dev->total_ctx, 0);
+ atomic_set(&dev->total_locks, 0);
+ atomic_set(&dev->total_unlocks, 0);
+ atomic_set(&dev->total_contends, 0);
+ atomic_set(&dev->total_sleeps, 0);
+
+ for (i = 0; i < DRM_HASH_SIZE; i++) {
+ dev->magiclist[i].head = NULL;
+ dev->magiclist[i].tail = NULL;
+ }
+
+ dev->maplist = NULL;
+ dev->map_count = 0;
+ dev->vmalist = NULL;
+ dev->lock.hw_lock = NULL;
+ init_waitqueue_head(&dev->lock.lock_queue);
+ dev->queue_count = 0;
+ dev->queue_reserved = 0;
+ dev->queue_slots = 0;
+ dev->queuelist = NULL;
+ dev->irq = 0;
+ dev->context_flag = 0;
+ dev->interrupt_flag = 0;
+ dev->dma = 0;
+ dev->dma_flag = 0;
+ dev->last_context = 0;
+ dev->last_switch = 0;
+ dev->last_checked = 0;
+ init_timer(&dev->timer);
+ init_waitqueue_head(&dev->context_wait);
+
+ dev->ctx_start = 0;
+ dev->lck_start = 0;
+
+ dev->buf_rp = dev->buf;
+ dev->buf_wp = dev->buf;
+ dev->buf_end = dev->buf + DRM_BSZ;
+ dev->buf_async = NULL;
+ init_waitqueue_head(&dev->buf_readers);
+ init_waitqueue_head(&dev->buf_writers);
+
+ return 0;
+}
+
+static int ffb_open(struct inode *inode, struct file *filp)
+{
+ drm_device_t *dev;
+ int minor, i;
+ int ret = 0;
+
+ minor = MINOR(inode->i_rdev);
+ for (i = 0; i < ffb_dev_table_size; i++) {
+ ffb_dev_priv_t *ffb_priv;
+
+ ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1);
+
+ if (ffb_priv->miscdev.minor == minor)
+ break;
+ }
+
+ if (i >= ffb_dev_table_size)
+ return -EINVAL;
+
+ dev = ffb_dev_table[i];
+ if (!dev)
+ return -EINVAL;
+
+ DRM_DEBUG("open_count = %d\n", dev->open_count);
+ ret = drm_open_helper(inode, filp, dev);
+ if (!ret) {
+ MOD_INC_USE_COUNT;
+ atomic_inc(&dev->total_open);
+ spin_lock(&dev->count_lock);
+ if (!dev->open_count++) {
+ spin_unlock(&dev->count_lock);
+ return ffb_setup(dev);
+ }
+ spin_unlock(&dev->count_lock);
+ }
+
+ return ret;
+}
+
+static int ffb_release(struct inode *inode, struct file *filp)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ int ret = 0;
+
+ DRM_DEBUG("open_count = %d\n", dev->open_count);
+ if (dev->lock.hw_lock != NULL
+ && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+ && dev->lock.pid == current->pid) {
+ ffb_dev_priv_t *fpriv = (ffb_dev_priv_t *) (dev + 1);
+ int context = _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock);
+ int idx;
+
+ /* We have to free up the rogue hw context state
+ * holding error or else we will leak it.
+ */
+ idx = context - 1;
+ if (fpriv->hw_state[idx] != NULL) {
+ kfree(fpriv->hw_state[idx]);
+ fpriv->hw_state[idx] = NULL;
+ }
+ }
+
+ ret = drm_release(inode, filp);
+
+ if (!ret) {
+ MOD_DEC_USE_COUNT;
+ atomic_inc(&dev->total_close);
+ spin_lock(&dev->count_lock);
+ if (!--dev->open_count) {
+ if (atomic_read(&dev->ioctl_count) || dev->blocked) {
+ DRM_ERROR("Device busy: %d %d\n",
+ atomic_read(&dev->ioctl_count),
+ dev->blocked);
+ spin_unlock(&dev->count_lock);
+ return -EBUSY;
+ }
+ spin_unlock(&dev->count_lock);
+ return ffb_takedown(dev);
+ }
+ spin_unlock(&dev->count_lock);
+ }
+
+ return ret;
+}
+
+static int ffb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int nr = DRM_IOCTL_NR(cmd);
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_ioctl_desc_t *ioctl;
+ drm_ioctl_t *func;
+ int ret;
+
+ atomic_inc(&dev->ioctl_count);
+ atomic_inc(&dev->total_ioctl);
+ ++priv->ioctl_count;
+
+ DRM_DEBUG("pid = %d, cmd = 0x%02x, nr = 0x%02x, dev 0x%x, auth = %d\n",
+ current->pid, cmd, nr, dev->device, priv->authenticated);
+
+ if (nr >= FFB_IOCTL_COUNT) {
+ ret = -EINVAL;
+ } else {
+ ioctl = &ffb_ioctls[nr];
+ func = ioctl->func;
+
+ if (!func) {
+ DRM_DEBUG("no function\n");
+ ret = -EINVAL;
+ } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
+ || (ioctl->auth_needed && !priv->authenticated)) {
+ ret = -EACCES;
+ } else {
+ ret = (func)(inode, filp, cmd, arg);
+ }
+ }
+
+ atomic_dec(&dev->ioctl_count);
+
+ return ret;
+}
+
+static int ffb_lock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ DECLARE_WAITQUEUE(entry, current);
+ int ret = 0;
+ drm_lock_t lock;
+
+ ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock));
+ if (ret)
+ return -EFAULT;
+
+ if (lock.context == DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Process %d using kernel context %d\n",
+ current->pid, lock.context);
+ return -EINVAL;
+ }
+
+ DRM_DEBUG("%d (pid %d) requests lock (0x%08x), flags = 0x%08x\n",
+ lock.context, current->pid, dev->lock.hw_lock->lock,
+ lock.flags);
+
+ add_wait_queue(&dev->lock.lock_queue, &entry);
+ for (;;) {
+ if (!dev->lock.hw_lock) {
+ /* Device has been unregistered */
+ ret = -EINTR;
+ break;
+ }
+ if (drm_lock_take(&dev->lock.hw_lock->lock,
+ lock.context)) {
+ dev->lock.pid = current->pid;
+ dev->lock.lock_time = jiffies;
+ atomic_inc(&dev->total_locks);
+ break; /* Got lock */
+ }
+
+ /* Contention */
+ atomic_inc(&dev->total_sleeps);
+ current->state = TASK_INTERRUPTIBLE;
+ current->policy |= SCHED_YIELD;
+ schedule();
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ }
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&dev->lock.lock_queue, &entry);
+
+ if (!ret &&
+ (dev->last_context != lock.context))
+ ffb_context_switch(dev, dev->last_context, lock.context);
+
+ DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+ return ret;
+}
+
+int ffb_unlock(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_lock_t lock;
+ unsigned int old, new, prev, ctx;
+ int ret;
+
+ ret = copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock));
+ if (ret)
+ return -EFAULT;
+
+ if ((ctx = lock.context) == DRM_KERNEL_CONTEXT) {
+ DRM_ERROR("Process %d using kernel context %d\n",
+ current->pid, lock.context);
+ return -EINVAL;
+ }
+
+ DRM_DEBUG("%d frees lock (%d holds)\n",
+ lock.context,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+ atomic_inc(&dev->total_unlocks);
+ if (_DRM_LOCK_IS_CONT(dev->lock.hw_lock->lock))
+ atomic_inc(&dev->total_contends);
+
+ /* We no longer really hold it, but if we are the next
+ * agent to request it then we should just be able to
+ * take it immediately and not eat the ioctl.
+ */
+ dev->lock.pid = 0;
+ {
+ __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock;
+
+ do {
+ old = *plock;
+ new = ctx;
+ prev = cmpxchg(plock, old, new);
+ } while (prev != old);
+ }
+
+ wake_up_interruptible(&dev->lock.lock_queue);
+
+ return 0;
+}
+
+static void align_fb_mapping(struct vm_area_struct *vma)
+{
+ unsigned long j, alignment;
+
+ j = vma->vm_end - vma->vm_start;
+ for (alignment = (4 * 1024 * 1024); alignment > PAGE_SIZE; alignment >>= 3)
+ if (j >= alignment)
+ break;
+ if (alignment > PAGE_SIZE) {
+ j = alignment;
+ alignment = j - (vma->vm_start & (j - 1));
+ if (alignment != j) {
+ struct vm_area_struct *vmm = find_vma(current->mm,vma->vm_start);
+
+ if (!vmm || vmm->vm_start >= vma->vm_end + alignment) {
+ vma->vm_start += alignment;
+ vma->vm_end += alignment;
+ }
+ }
+ }
+}
+
+/* The problem here is, due to virtual cache aliasing,
+ * we must make sure the shared memory area lands in the
+ * same dcache line for both the kernel and all drm clients.
+ */
+static void align_shm_mapping(struct vm_area_struct *vma, unsigned long kvirt)
+{
+ kvirt &= PAGE_SIZE;
+ if ((vma->vm_start & PAGE_SIZE) != kvirt) {
+ struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start);
+
+ if (!vmm || vmm->vm_start >= vma->vm_end + PAGE_SIZE) {
+ vma->vm_start += PAGE_SIZE;
+ vma->vm_end += PAGE_SIZE;
+ }
+ }
+}
+
+extern struct vm_operations_struct drm_vm_ops;
+extern struct vm_operations_struct drm_vm_shm_ops;
+
+static int ffb_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->dev;
+ drm_map_t *map = NULL;
+ ffb_dev_priv_t *ffb_priv;
+ int i, minor;
+
+ DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
+ vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+
+ minor = MINOR(filp->f_dentry->d_inode->i_rdev);
+ ffb_priv = NULL;
+ for (i = 0; i < ffb_dev_table_size; i++) {
+ ffb_priv = (ffb_dev_priv_t *) (ffb_dev_table[i] + 1);
+ if (ffb_priv->miscdev.minor == minor)
+ break;
+ }
+ if (i >= ffb_dev_table_size)
+ return -EINVAL;
+
+ /* We don't support/need dma mappings, so... */
+ if (!VM_OFFSET(vma))
+ return -EINVAL;
+
+ for (i = 0; i < dev->map_count; i++) {
+ unsigned long off;
+
+ map = dev->maplist[i];
+
+ /* Ok, a little hack to make 32-bit apps work. */
+ off = (map->offset & 0xffffffff);
+ if (off == VM_OFFSET(vma))
+ break;
+ }
+
+ if (i >= dev->map_count)
+ return -EINVAL;
+
+ if (!map ||
+ ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
+ return -EPERM;
+
+ if (map->size != (vma->vm_end - vma->vm_start))
+ return -EINVAL;
+
+ /* Set read-only attribute before mappings are created
+ * so it works for fb/reg maps too.
+ */
+ if (map->flags & _DRM_READ_ONLY)
+ vma->vm_page_prot = __pgprot(pte_val(pte_wrprotect(
+ __pte(pgprot_val(vma->vm_page_prot)))));
+
+ switch (map->type) {
+ case _DRM_FRAME_BUFFER:
+ align_fb_mapping(vma);
+ /* FALLTHROUGH */
+
+ case _DRM_REGISTERS:
+ /* In order to handle 32-bit drm apps/xserver we
+ * play a trick. The mappings only really specify
+ * the 32-bit offset from the cards 64-bit base
+ * address, and we just add in the base here.
+ */
+ vma->vm_flags |= VM_IO;
+ if (io_remap_page_range(vma->vm_start,
+ ffb_priv->card_phys_base + VM_OFFSET(vma),
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot, 0))
+ return -EAGAIN;
+
+ vma->vm_ops = &drm_vm_ops;
+ break;
+ case _DRM_SHM:
+ align_shm_mapping(vma, (unsigned long)dev->lock.hw_lock);
+ vma->vm_ops = &drm_vm_shm_ops;
+
+ /* Don't let this area swap. Change when
+ * DRM_KERNEL advisory is supported.
+ */
+ vma->vm_flags |= VM_LOCKED;
+ break;
+ default:
+ return -EINVAL; /* This should never happen. */
+ };
+
+ vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */
+
+ vma->vm_file = filp; /* Needed for drm_vm_open() */
+ drm_vm_open(vma);
+ return 0;
+}
+
+module_init(ffb_init);
+module_exit(ffb_cleanup);
diff --git a/drivers/char/drm/ffb_drv.h b/drivers/char/drm/ffb_drv.h
new file mode 100644
index 000000000..094bbce09
--- /dev/null
+++ b/drivers/char/drm/ffb_drv.h
@@ -0,0 +1,276 @@
+/* $Id: ffb_drv.h,v 1.1 2000/06/01 04:24:39 davem Exp $
+ * ffb_drv.h: Creator/Creator3D direct rendering driver.
+ *
+ * Copyright (C) 2000 David S. Miller (davem@redhat.com)
+ */
+
+/* Auxilliary clips. */
+typedef struct {
+ volatile unsigned int min;
+ volatile unsigned int max;
+} ffb_auxclip, *ffb_auxclipPtr;
+
+/* FFB register set. */
+typedef struct _ffb_fbc {
+ /* Next vertex registers, on the right we list which drawops
+ * use said register and the logical name the register has in
+ * that context.
+ */ /* DESCRIPTION DRAWOP(NAME) */
+/*0x00*/unsigned int pad1[3]; /* Reserved */
+/*0x0c*/volatile unsigned int alpha; /* ALPHA Transparency */
+/*0x10*/volatile unsigned int red; /* RED */
+/*0x14*/volatile unsigned int green; /* GREEN */
+/*0x18*/volatile unsigned int blue; /* BLUE */
+/*0x1c*/volatile unsigned int z; /* DEPTH */
+/*0x20*/volatile unsigned int y; /* Y triangle(DOYF) */
+ /* aadot(DYF) */
+ /* ddline(DYF) */
+ /* aaline(DYF) */
+/*0x24*/volatile unsigned int x; /* X triangle(DOXF) */
+ /* aadot(DXF) */
+ /* ddline(DXF) */
+ /* aaline(DXF) */
+/*0x28*/unsigned int pad2[2]; /* Reserved */
+/*0x30*/volatile unsigned int ryf; /* Y (alias to DOYF) ddline(RYF) */
+ /* aaline(RYF) */
+ /* triangle(RYF) */
+/*0x34*/volatile unsigned int rxf; /* X ddline(RXF) */
+ /* aaline(RXF) */
+ /* triangle(RXF) */
+/*0x38*/unsigned int pad3[2]; /* Reserved */
+/*0x40*/volatile unsigned int dmyf; /* Y (alias to DOYF) triangle(DMYF) */
+/*0x44*/volatile unsigned int dmxf; /* X triangle(DMXF) */
+/*0x48*/unsigned int pad4[2]; /* Reserved */
+/*0x50*/volatile unsigned int ebyi; /* Y (alias to RYI) polygon(EBYI) */
+/*0x54*/volatile unsigned int ebxi; /* X polygon(EBXI) */
+/*0x58*/unsigned int pad5[2]; /* Reserved */
+/*0x60*/volatile unsigned int by; /* Y brline(RYI) */
+ /* fastfill(OP) */
+ /* polygon(YI) */
+ /* rectangle(YI) */
+ /* bcopy(SRCY) */
+ /* vscroll(SRCY) */
+/*0x64*/volatile unsigned int bx; /* X brline(RXI) */
+ /* polygon(XI) */
+ /* rectangle(XI) */
+ /* bcopy(SRCX) */
+ /* vscroll(SRCX) */
+ /* fastfill(GO) */
+/*0x68*/volatile unsigned int dy; /* destination Y fastfill(DSTY) */
+ /* bcopy(DSRY) */
+ /* vscroll(DSRY) */
+/*0x6c*/volatile unsigned int dx; /* destination X fastfill(DSTX) */
+ /* bcopy(DSTX) */
+ /* vscroll(DSTX) */
+/*0x70*/volatile unsigned int bh; /* Y (alias to RYI) brline(DYI) */
+ /* dot(DYI) */
+ /* polygon(ETYI) */
+ /* Height fastfill(H) */
+ /* bcopy(H) */
+ /* vscroll(H) */
+ /* Y count fastfill(NY) */
+/*0x74*/volatile unsigned int bw; /* X dot(DXI) */
+ /* brline(DXI) */
+ /* polygon(ETXI) */
+ /* fastfill(W) */
+ /* bcopy(W) */
+ /* vscroll(W) */
+ /* fastfill(NX) */
+/*0x78*/unsigned int pad6[2]; /* Reserved */
+/*0x80*/unsigned int pad7[32]; /* Reserved */
+
+ /* Setup Unit's vertex state register */
+/*100*/ volatile unsigned int suvtx;
+/*104*/ unsigned int pad8[63]; /* Reserved */
+
+ /* Frame Buffer Control Registers */
+/*200*/ volatile unsigned int ppc; /* Pixel Processor Control */
+/*204*/ volatile unsigned int wid; /* Current WID */
+/*208*/ volatile unsigned int fg; /* FG data */
+/*20c*/ volatile unsigned int bg; /* BG data */
+/*210*/ volatile unsigned int consty; /* Constant Y */
+/*214*/ volatile unsigned int constz; /* Constant Z */
+/*218*/ volatile unsigned int xclip; /* X Clip */
+/*21c*/ volatile unsigned int dcss; /* Depth Cue Scale Slope */
+/*220*/ volatile unsigned int vclipmin; /* Viewclip XY Min Bounds */
+/*224*/ volatile unsigned int vclipmax; /* Viewclip XY Max Bounds */
+/*228*/ volatile unsigned int vclipzmin; /* Viewclip Z Min Bounds */
+/*22c*/ volatile unsigned int vclipzmax; /* Viewclip Z Max Bounds */
+/*230*/ volatile unsigned int dcsf; /* Depth Cue Scale Front Bound */
+/*234*/ volatile unsigned int dcsb; /* Depth Cue Scale Back Bound */
+/*238*/ volatile unsigned int dczf; /* Depth Cue Z Front */
+/*23c*/ volatile unsigned int dczb; /* Depth Cue Z Back */
+/*240*/ unsigned int pad9; /* Reserved */
+/*244*/ volatile unsigned int blendc; /* Alpha Blend Control */
+/*248*/ volatile unsigned int blendc1; /* Alpha Blend Color 1 */
+/*24c*/ volatile unsigned int blendc2; /* Alpha Blend Color 2 */
+/*250*/ volatile unsigned int fbramitc; /* FB RAM Interleave Test Control */
+/*254*/ volatile unsigned int fbc; /* Frame Buffer Control */
+/*258*/ volatile unsigned int rop; /* Raster OPeration */
+/*25c*/ volatile unsigned int cmp; /* Frame Buffer Compare */
+/*260*/ volatile unsigned int matchab; /* Buffer AB Match Mask */
+/*264*/ volatile unsigned int matchc; /* Buffer C(YZ) Match Mask */
+/*268*/ volatile unsigned int magnab; /* Buffer AB Magnitude Mask */
+/*26c*/ volatile unsigned int magnc; /* Buffer C(YZ) Magnitude Mask */
+/*270*/ volatile unsigned int fbcfg0; /* Frame Buffer Config 0 */
+/*274*/ volatile unsigned int fbcfg1; /* Frame Buffer Config 1 */
+/*278*/ volatile unsigned int fbcfg2; /* Frame Buffer Config 2 */
+/*27c*/ volatile unsigned int fbcfg3; /* Frame Buffer Config 3 */
+/*280*/ volatile unsigned int ppcfg; /* Pixel Processor Config */
+/*284*/ volatile unsigned int pick; /* Picking Control */
+/*288*/ volatile unsigned int fillmode; /* FillMode */
+/*28c*/ volatile unsigned int fbramwac; /* FB RAM Write Address Control */
+/*290*/ volatile unsigned int pmask; /* RGB PlaneMask */
+/*294*/ volatile unsigned int xpmask; /* X PlaneMask */
+/*298*/ volatile unsigned int ypmask; /* Y PlaneMask */
+/*29c*/ volatile unsigned int zpmask; /* Z PlaneMask */
+/*2a0*/ ffb_auxclip auxclip[4]; /* Auxilliary Viewport Clip */
+
+ /* New 3dRAM III support regs */
+/*2c0*/ volatile unsigned int rawblend2;
+/*2c4*/ volatile unsigned int rawpreblend;
+/*2c8*/ volatile unsigned int rawstencil;
+/*2cc*/ volatile unsigned int rawstencilctl;
+/*2d0*/ volatile unsigned int threedram1;
+/*2d4*/ volatile unsigned int threedram2;
+/*2d8*/ volatile unsigned int passin;
+/*2dc*/ volatile unsigned int rawclrdepth;
+/*2e0*/ volatile unsigned int rawpmask;
+/*2e4*/ volatile unsigned int rawcsrc;
+/*2e8*/ volatile unsigned int rawmatch;
+/*2ec*/ volatile unsigned int rawmagn;
+/*2f0*/ volatile unsigned int rawropblend;
+/*2f4*/ volatile unsigned int rawcmp;
+/*2f8*/ volatile unsigned int rawwac;
+/*2fc*/ volatile unsigned int fbramid;
+
+/*300*/ volatile unsigned int drawop; /* Draw OPeration */
+/*304*/ unsigned int pad10[2]; /* Reserved */
+/*30c*/ volatile unsigned int lpat; /* Line Pattern control */
+/*310*/ unsigned int pad11; /* Reserved */
+/*314*/ volatile unsigned int fontxy; /* XY Font coordinate */
+/*318*/ volatile unsigned int fontw; /* Font Width */
+/*31c*/ volatile unsigned int fontinc; /* Font Increment */
+/*320*/ volatile unsigned int font; /* Font bits */
+/*324*/ unsigned int pad12[3]; /* Reserved */
+/*330*/ volatile unsigned int blend2;
+/*334*/ volatile unsigned int preblend;
+/*338*/ volatile unsigned int stencil;
+/*33c*/ volatile unsigned int stencilctl;
+
+/*340*/ unsigned int pad13[4]; /* Reserved */
+/*350*/ volatile unsigned int dcss1; /* Depth Cue Scale Slope 1 */
+/*354*/ volatile unsigned int dcss2; /* Depth Cue Scale Slope 2 */
+/*358*/ volatile unsigned int dcss3; /* Depth Cue Scale Slope 3 */
+/*35c*/ volatile unsigned int widpmask;
+/*360*/ volatile unsigned int dcs2;
+/*364*/ volatile unsigned int dcs3;
+/*368*/ volatile unsigned int dcs4;
+/*36c*/ unsigned int pad14; /* Reserved */
+/*370*/ volatile unsigned int dcd2;
+/*374*/ volatile unsigned int dcd3;
+/*378*/ volatile unsigned int dcd4;
+/*37c*/ unsigned int pad15; /* Reserved */
+/*380*/ volatile unsigned int pattern[32]; /* area Pattern */
+/*400*/ unsigned int pad16[8]; /* Reserved */
+/*420*/ volatile unsigned int reset; /* chip RESET */
+/*424*/ unsigned int pad17[247]; /* Reserved */
+/*800*/ volatile unsigned int devid; /* Device ID */
+/*804*/ unsigned int pad18[63]; /* Reserved */
+/*900*/ volatile unsigned int ucsr; /* User Control & Status Register */
+/*904*/ unsigned int pad19[31]; /* Reserved */
+/*980*/ volatile unsigned int mer; /* Mode Enable Register */
+/*984*/ unsigned int pad20[1439]; /* Reserved */
+} ffb_fbc, *ffb_fbcPtr;
+
+struct ffb_hw_context {
+ int is_2d_only;
+
+ unsigned int ppc;
+ unsigned int wid;
+ unsigned int fg;
+ unsigned int bg;
+ unsigned int consty;
+ unsigned int constz;
+ unsigned int xclip;
+ unsigned int dcss;
+ unsigned int vclipmin;
+ unsigned int vclipmax;
+ unsigned int vclipzmin;
+ unsigned int vclipzmax;
+ unsigned int dcsf;
+ unsigned int dcsb;
+ unsigned int dczf;
+ unsigned int dczb;
+ unsigned int blendc;
+ unsigned int blendc1;
+ unsigned int blendc2;
+ unsigned int fbc;
+ unsigned int rop;
+ unsigned int cmp;
+ unsigned int matchab;
+ unsigned int matchc;
+ unsigned int magnab;
+ unsigned int magnc;
+ unsigned int pmask;
+ unsigned int xpmask;
+ unsigned int ypmask;
+ unsigned int zpmask;
+ unsigned int auxclip0min;
+ unsigned int auxclip0max;
+ unsigned int auxclip1min;
+ unsigned int auxclip1max;
+ unsigned int auxclip2min;
+ unsigned int auxclip2max;
+ unsigned int auxclip3min;
+ unsigned int auxclip3max;
+ unsigned int drawop;
+ unsigned int lpat;
+ unsigned int fontxy;
+ unsigned int fontw;
+ unsigned int fontinc;
+ unsigned int area_pattern[32];
+ unsigned int ucsr;
+ unsigned int stencil;
+ unsigned int stencilctl;
+ unsigned int dcss1;
+ unsigned int dcss2;
+ unsigned int dcss3;
+ unsigned int dcs2;
+ unsigned int dcs3;
+ unsigned int dcs4;
+ unsigned int dcd2;
+ unsigned int dcd3;
+ unsigned int dcd4;
+ unsigned int mer;
+};
+
+#define FFB_MAX_CTXS 32
+
+enum ffb_chip_type {
+ ffb1_prototype = 0, /* Early pre-FCS FFB */
+ ffb1_standard, /* First FCS FFB, 100Mhz UPA, 66MHz gclk */
+ ffb1_speedsort, /* Second FCS FFB, 100Mhz UPA, 75MHz gclk */
+ ffb2_prototype, /* Early pre-FCS vertical FFB2 */
+ ffb2_vertical, /* First FCS FFB2/vertical, 100Mhz UPA, 100MHZ gclk,
+ 75(SingleBuffer)/83(DoubleBuffer) MHz fclk */
+ ffb2_vertical_plus, /* Second FCS FFB2/vertical, same timings */
+ ffb2_horizontal, /* First FCS FFB2/horizontal, same timings as FFB2/vert */
+ ffb2_horizontal_plus, /* Second FCS FFB2/horizontal, same timings */
+ afb_m3, /* FCS Elite3D, 3 float chips */
+ afb_m6 /* FCS Elite3D, 6 float chips */
+};
+
+typedef struct ffb_dev_priv {
+ /* Misc software state. */
+ int prom_node;
+ enum ffb_chip_type ffb_type;
+ u64 card_phys_base;
+ struct miscdevice miscdev;
+
+ /* Controller registers. */
+ ffb_fbcPtr regs;
+
+ /* Context table. */
+ struct ffb_hw_context *hw_state[FFB_MAX_CTXS];
+} ffb_dev_priv_t;
diff --git a/drivers/char/drm/fops.c b/drivers/char/drm/fops.c
index a823db356..76e0dc2c1 100644
--- a/drivers/char/drm/fops.c
+++ b/drivers/char/drm/fops.c
@@ -92,7 +92,8 @@ int drm_release(struct inode *inode, struct file *filp)
DRM_DEBUG("pid = %d, device = 0x%x, open_count = %d\n",
current->pid, dev->device, dev->open_count);
- if (_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
+ if (dev->lock.hw_lock != NULL
+ && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
&& dev->lock.pid == current->pid) {
DRM_ERROR("Process %d dead, freeing lock for context %d\n",
current->pid,
@@ -216,7 +217,7 @@ int drm_write_string(drm_device_t *dev, const char *s)
if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO);
#else
/* Parameter added in 2.3.21 */
- if (dev->buf_async) kill_fasync(dev->buf_async, SIGIO, POLL_IN);
+ kill_fasync(&dev->buf_async, SIGIO, POLL_IN);
#endif
DRM_DEBUG("waking\n");
wake_up_interruptible(&dev->buf_readers);
diff --git a/drivers/char/drm/init.c b/drivers/char/drm/init.c
index 7a0115e86..ad887490b 100644
--- a/drivers/char/drm/init.c
+++ b/drivers/char/drm/init.c
@@ -104,5 +104,9 @@ int drm_cpu_valid(void)
#if defined(__i386__)
if (boot_cpu_data.x86 == 3) return 0; /* No cmpxchg on a 386 */
#endif
+#if defined(__sparc__) && !defined(__sparc_v9__)
+ if (1)
+ return 0; /* No cmpxchg before v9 sparc. */
+#endif
return 1;
}
diff --git a/drivers/char/drm/proc.c b/drivers/char/drm/proc.c
index 4d5d1a964..d44195539 100644
--- a/drivers/char/drm/proc.c
+++ b/drivers/char/drm/proc.c
@@ -512,9 +512,9 @@ static int _drm_histo_info(char *buf, char **start, off_t offset, int len,
} else {
DRM_PROC_PRINT("lock none\n");
}
- DRM_PROC_PRINT("context_flag 0x%08x\n", dev->context_flag);
- DRM_PROC_PRINT("interrupt_flag 0x%08x\n", dev->interrupt_flag);
- DRM_PROC_PRINT("dma_flag 0x%08x\n", dev->dma_flag);
+ DRM_PROC_PRINT("context_flag 0x%08lx\n", dev->context_flag);
+ DRM_PROC_PRINT("interrupt_flag 0x%08lx\n", dev->interrupt_flag);
+ DRM_PROC_PRINT("dma_flag 0x%08lx\n", dev->dma_flag);
DRM_PROC_PRINT("queue_count %10d\n", dev->queue_count);
DRM_PROC_PRINT("last_context %10d\n", dev->last_context);
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c
index 5a89e008a..f0c76181b 100644
--- a/drivers/char/ds1620.c
+++ b/drivers/char/ds1620.c
@@ -311,22 +311,6 @@ ds1620_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned
return 0;
}
-static int
-ds1620_open(struct inode *inode, struct file *file)
-{
- MOD_INC_USE_COUNT;
-
- return 0;
-}
-
-static int
-ds1620_release(struct inode *inode, struct file *file)
-{
- MOD_DEC_USE_COUNT;
-
- return 0;
-}
-
#ifdef THERM_USE_PROC
static int
proc_therm_ds1620_read(char *buf, char **start, off_t offset,
@@ -352,10 +336,9 @@ static struct proc_dir_entry *proc_therm_ds1620;
#endif
static struct file_operations ds1620_fops = {
+ owner: THIS_MODULE,
read: ds1620_read,
ioctl: ds1620_ioctl,
- open: ds1620_open,
- release: ds1620_release,
};
static struct miscdevice ds1620_miscdev = {
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index ac27c9e0e..dc076dd5a 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -472,10 +472,6 @@ static int dsp56k_open(struct inode *inode, struct file *file)
return -ENXIO;
}
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif /* MODULE */
-
return 0;
}
@@ -495,13 +491,11 @@ static int dsp56k_release(struct inode *inode, struct file *file)
return -ENXIO;
}
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
return 0;
}
static struct file_operations dsp56k_fops = {
+ owner: THIS_MODULE,
read: dsp56k_read,
write: dsp56k_write,
ioctl: dsp56k_ioctl,
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index 542ad99bf..730b69b17 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -102,6 +102,7 @@ static int dtlk_ioctl(struct inode *inode, struct file *file,
static struct file_operations dtlk_fops =
{
+ owner: THIS_MODULE,
read: dtlk_read,
write: dtlk_write,
poll: dtlk_poll,
@@ -306,7 +307,6 @@ static int dtlk_ioctl(struct inode *inode,
static int dtlk_open(struct inode *inode, struct file *file)
{
- MOD_INC_USE_COUNT;
TRACE_TEXT("(dtlk_open");
switch (MINOR(inode->i_rdev)) {
@@ -322,7 +322,6 @@ static int dtlk_open(struct inode *inode, struct file *file)
static int dtlk_release(struct inode *inode, struct file *file)
{
- MOD_DEC_USE_COUNT;
TRACE_TEXT("(dtlk_release");
switch (MINOR(inode->i_rdev)) {
diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c
index 103e60eef..9ad85c687 100644
--- a/drivers/char/efirtc.c
+++ b/drivers/char/efirtc.c
@@ -281,6 +281,7 @@ efi_rtc_close(struct inode *inode, struct file *file)
*/
static struct file_operations efi_rtc_fops = {
+ owner: THIS_MODULE,
ioctl: efi_rtc_ioctl,
open: efi_rtc_open,
release: efi_rtc_close,
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 9238ae3eb..13656af4b 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -4007,6 +4007,9 @@ static int __init epca_init_one (struct pci_dev *pdev,
int board_idx, info_idx = ent->driver_data;
unsigned long addr;
+ if (pci_enable_device(pdev))
+ return -EIO;
+
board_num++;
board_idx = board_num + num_cards;
if (board_idx >= MAXBOARDS)
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index dfe89b970..01eb20e92 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -330,7 +330,7 @@ int gs_chars_in_buffer(struct tty_struct *tty)
int gs_real_chars_in_buffer(struct tty_struct *tty)
{
- struct gs_port *port = tty->driver_data;
+ struct gs_port *port;
func_enter ();
if (!tty) return 0;
diff --git a/drivers/char/hp600_keyb.c b/drivers/char/hp600_keyb.c
new file mode 100644
index 000000000..52f66ba5f
--- /dev/null
+++ b/drivers/char/hp600_keyb.c
@@ -0,0 +1,119 @@
+/*
+ * $Id: hp600_keyb.c,v 1.1 2000/06/10 21:45:30 yaegashi Exp $
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ * HP600 keyboard scan routine and translate table
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include "scan_keyb.h"
+
+#define PCDR 0xa4000124
+#define PDDR 0xa4000126
+#define PEDR 0xa4000128
+#define PFDR 0xa400012a
+#define PGDR 0xa400012c
+#define PHDR 0xa400012e
+
+static const unsigned char hp690_japanese_table[]={
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x29, 0x70, 0x3a,
+ 0x3f, 0x3e, 0x40, 0x41, 0x42, 0x3d, 0x3c, 0x3b,
+
+ 0x00, 0x00, 0x00, 0x2c, 0x00, 0x1c, 0x28, 0x35,
+ 0x31, 0x30, 0x32, 0x33, 0x34, 0x2f, 0x2e, 0x2d,
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x50,
+ 0x7b, 0x38, 0x00, 0x00, 0x4b, 0x00, 0x00, 0x00,
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xf9, 0x73, 0x53, 0x39, 0x00, 0x1d,
+
+ 0x00, 0x00, 0x00, 0x1e, 0x00, 0x2b, 0x1b, 0x27,
+ 0x23, 0x22, 0x24, 0x25, 0x26, 0x21, 0x20, 0x1f,
+
+ 0x00, 0x00, 0x00, 0x0f, 0x00, 0x36, 0x7d, 0x48,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00,
+
+ 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x1a, 0x19,
+ 0x15, 0x14, 0x16, 0x17, 0x18, 0x13, 0x12, 0x11,
+
+ 0x00, 0x00, 0x00, 0x02, 0x00, 0x0d, 0x0c, 0x0b,
+ 0x07, 0x06, 0x08, 0x09, 0x0a, 0x05, 0x04, 0x03,
+
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+
+static void hp690_japanese_scan_kbd(unsigned char *s)
+{
+ ctrl_outb(0xfd, PDDR); ctrl_outb(0xff, PEDR);
+ *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR);
+ ctrl_outb(0xdf, PDDR); ctrl_outb(0xff, PEDR);
+ *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR);
+ ctrl_outb(0x7f, PDDR); ctrl_outb(0xff, PEDR);
+ *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR);
+ ctrl_outb(0xff, PDDR); ctrl_outb(0xfe, PEDR);
+ *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR);
+ ctrl_outb(0xff, PDDR); ctrl_outb(0xfd, PEDR);
+ *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR);
+ ctrl_outb(0xff, PDDR); ctrl_outb(0xf7, PEDR);
+ *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR);
+ ctrl_outb(0xff, PDDR); ctrl_outb(0xbf, PEDR);
+ *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR);
+ ctrl_outb(0xff, PDDR); ctrl_outb(0x7f, PEDR);
+ *s++=ctrl_inb(PCDR); *s++=ctrl_inb(PFDR);
+ *s++=ctrl_inb(PGDR); *s++=ctrl_inb(PHDR);
+}
+
+
+void __init hp600_kbd_init_hw(void)
+{
+ scan_kbd_init();
+ register_scan_keyboard(hp690_japanese_scan_kbd,
+ hp690_japanese_table, 18);
+ printk(KERN_INFO "HP600 matrix scan keyboard registered\n");
+}
+
+
+/****************************************************************
+HP Jornada 690(Japanese version) keyboard scan matrix
+
+ PTC7 PTC6 PTC5 PTC4 PTC3 PTC2 PTC1 PTC0
+PTD1 REC Escape on/off Han/Zen Hira Eisu
+PTD5 REC Z on/off Enter : /
+PTD7 REC Right Down
+PTE0 REC Windows on/off
+PTE1 REC A on/off ] [ ;
+PTE3 REC Tab on/off ShirtR \ Up
+PTE6 REC Q on/off BS @ P
+PTE7 REC 1 on/off ^ - 0
+
+
+ PTF7 PTF6 PTF5 PTF4 PTF3 PTF2 PTF1 PTF0
+PTD1 F5 F4 F6 F7 F8 F3 F2 F1
+PTD5 N B M , . V C X
+PTD7 Muhen Alt Left
+PTE0 Henkan _ Del Space Ctrl
+PTE1 H G J K L F D S
+PTE3 ShiftL
+PTE6 Y T U I O R E W
+PTE7 6 5 7 8 9 4 3 2
+
+ PTG5 PTG4 PTG3 PTG0 PTH0
+* REC REW FWW Cover on/off
+
+
+ 7 6 5 4 3 2 1 0
+C: 0xffff 0xdf IP IP IP IP IP IP IP IP
+D: 0x6786 0x59 O I O IP I F O I
+E: 0x5045 0x00 O O F F O F O O
+F: 0xffff 0xff IP IP IP IP IP IP IP IP
+G: 0xaffe 0xfd I I IP IP IP IP IP I
+H: 0x70f2 0x49 O IP F F IP IP F I
+J: 0x0704 0x22 F F O IP F F O F
+K: 0x0100 0x10 F F F O F F F F
+L: 0x0c3c 0x26 F F IP F F IP IP F
+
+****************************************************************/
diff --git a/drivers/char/i2c-old.c b/drivers/char/i2c-old.c
index bd9750fc3..b509c9a18 100644
--- a/drivers/char/i2c-old.c
+++ b/drivers/char/i2c-old.c
@@ -37,8 +37,8 @@ static struct i2c_driver *drivers[I2C_DRIVER_MAX];
static int bus_count = 0, driver_count = 0;
#ifdef CONFIG_VIDEO_BT848
-extern int i2c_tuner_init(void);
-extern int msp3400c_init(void);
+extern int tuner_init_module(void);
+extern int msp3400_init_module(void);
#endif
#ifdef CONFIG_VIDEO_BUZ
extern int saa7111_init(void);
@@ -55,8 +55,8 @@ int i2c_init(void)
scan ? " (i2c bus scan enabled)" : "");
/* anything to do here ? */
#ifdef CONFIG_VIDEO_BT848
- i2c_tuner_init();
- msp3400c_init();
+ tuner_init_module();
+ msp3400_init_module();
#endif
#ifdef CONFIG_VIDEO_BUZ
saa7111_init();
diff --git a/drivers/char/i810_rng.c b/drivers/char/i810_rng.c
new file mode 100644
index 000000000..191ce5001
--- /dev/null
+++ b/drivers/char/i810_rng.c
@@ -0,0 +1,885 @@
+/*
+
+ Hardware driver for Intel i810 Random Number Generator (RNG)
+ Copyright 2000 Jeff Garzik <jgarzik@mandrakesoft.com>
+
+ Driver Web site: http://gtf.org/garzik/drivers/i810_rng/
+
+
+
+ Based on:
+ Intel 82802AB/82802AC Firmware Hub (FWH) Datasheet
+ May 1999 Order Number: 290658-002 R
+
+ Intel 82802 Firmware Hub: Random Number Generator
+ Programmer's Reference Manual
+ December 1999 Order Number: 298029-001 R
+
+ Intel 82802 Firmware HUB Random Number Generator Driver
+ Copyright (c) 2000 Matt Sottek <msottek@quiknet.com>
+
+ Special thanks to Matt Sottek. I did the "guts", he
+ did the "brains" and all the testing. (Anybody wanna send
+ me an i810 or i820?)
+
+ ----------------------------------------------------------
+
+ This software may be used and distributed according to the terms
+ of the GNU Public License, incorporated herein by reference.
+
+ ----------------------------------------------------------
+
+ From the firmware hub datasheet:
+
+ The Firmware Hub integrates a Random Number Generator (RNG)
+ using thermal noise generated from inherently random quantum
+ mechanical properties of silicon. When not generating new random
+ bits the RNG circuitry will enter a low power state. Intel will
+ provide a binary software driver to give third party software
+ access to our RNG for use as a security feature. At this time,
+ the RNG is only to be used with a system in an OS-present state.
+
+ ----------------------------------------------------------
+
+ Theory of operation:
+
+ This driver has TWO modes of operation:
+
+ Mode 1
+ ------
+ Character driver. Using the standard open()
+ and read() system calls, you can read random data from
+ the i810 RNG device. This data is NOT CHECKED by any
+ fitness tests, and could potentially be bogus (if the
+ hardware is faulty or has been tampered with).
+
+ /dev/intel_rng is char device major 10, minor 183.
+
+
+ Mode 2
+ ------
+ Injection of entropy into the kernel entropy pool via a
+ timer function.
+
+ A timer is run at RNG_TIMER_LEN intervals, reading 8 bits
+ of data from the RNG. If the RNG has previously passed a
+ FIPS test, then the data will be added to the /dev/random
+ entropy pool. Then, those 8 bits are added to an internal
+ test data pool. When that pool is full, a FIPS test is
+ run to verify that the last N bytes read are decently random.
+
+ Thus, the RNG will never be enabled until it passes a
+ FIPS test. And, data will stop flowing into the system
+ entropy pool if the data is determined to be non-random.
+
+ Finally, note that the timer defaults to OFF. This ensures
+ that the system entropy pool will not be polluted with
+ RNG-originated data unless a conscious decision is made
+ by the user.
+
+ HOWEVER NOTE THAT UP TO 2499 BYTES OF DATA CAN BE BOGUS
+ BEFORE THE SYSTEM WILL NOTICE VIA THE FIPS TEST.
+
+ ----------------------------------------------------------
+
+ Driver notes:
+
+ * You may enable and disable the RNG hardware (and this
+ driver) via sysctl:
+
+ # disable RNG
+ echo 0 > /proc/sys/dev/i810_hw_enabled
+
+ # enable RNG
+ echo 1 > /proc/sys/dev/i810_hw_enabled
+
+ * The default number of entropy bits added by default is
+ the full 8 bits. If you wish to reduce this value for
+ paranoia's sake, you can do so via sysctl as well:
+
+ # Add only 4 bits of entropy to /dev/random
+ echo 4 > /proc/sys/dev/i810_rng_entropy
+
+ * The default number of entropy bits can also be set via
+ a module parameter "rng_entropy" at module load time.
+
+ * In order to unload the i810_rng module, you must first
+ disable the hardware via sysctl i810_hw_enabled, as shown above,
+ and make sure all users of the character device
+
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/random.h>
+#include <linux/sysctl.h>
+#include <linux/miscdevice.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+
+/*
+ * core module and version information
+ */
+#define RNG_VERSION "0.6.1"
+#define RNG_MODULE_NAME "i810_rng"
+#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION
+#define PFX RNG_MODULE_NAME ": "
+
+
+/*
+ * debugging macros
+ */
+#undef RNG_DEBUG /* define to 1 to enable copious debugging info */
+
+#ifdef RNG_DEBUG
+/* note: prints function name for you */
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#define RNG_NDEBUG 0 /* define to 1 to disable lightweight runtime checks */
+#if RNG_NDEBUG
+#define assert(expr)
+#else
+#define assert(expr) \
+ if(!(expr)) { \
+ printk( "Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr,__FILE__,__FUNCTION__,__LINE__); \
+ }
+#endif
+
+
+/*
+ * misc helper macros
+ */
+#define arraysize(x) (sizeof(x)/sizeof(*(x)))
+
+/*
+ * prototypes
+ */
+static void rng_fips_test_store (int rng_data);
+static void rng_run_fips_test (void);
+
+
+/*
+ * RNG registers (offsets from rng_mem)
+ */
+#define RNG_HW_STATUS 0
+#define RNG_PRESENT 0x40
+#define RNG_ENABLED 0x01
+#define RNG_STATUS 1
+#define RNG_DATA_PRESENT 0x01
+#define RNG_DATA 2
+
+#define RNG_ADDR 0xFFBC015F
+#define RNG_ADDR_LEN 3
+
+#define RNG_MAX_ENTROPY 8 /* max entropy h/w is capable of */
+
+#define RNG_MISCDEV_MINOR 183 /* official */
+
+
+/*
+ * Frequency that data is added to kernel entropy pool
+ * HZ>>1 == every half-second
+ */
+#define RNG_TIMER_LEN (HZ >> 1)
+
+
+/*
+ * number of bytes required for a FIPS test.
+ * do not alter unless you really, I mean
+ * REALLY know what you are doing.
+ */
+#define RNG_FIPS_TEST_THRESHOLD 2500
+
+
+/*
+ * various RNG status variables. they are globals
+ * as we only support a single RNG device
+ */
+static int rng_allocated = 0; /* is someone using the RNG region? */
+static int rng_hw_enabled = 0; /* is the RNG h/w, and timer, enabled? */
+static int rng_trusted = 0; /* does FIPS trust out data? */
+static int rng_enabled_sysctl; /* sysctl for enabling/disabling RNG */
+static int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */
+static int rng_entropy_sysctl; /* sysctl for changing entropy bits */
+static int rng_have_mem_region = 0; /* did we grab RNG region via request_mem_region? */
+static int rng_fips_counter = 0; /* size of internal FIPS test data pool */
+static void *rng_mem = NULL; /* token to our ioremap'd RNG register area */
+static spinlock_t rng_lock = SPIN_LOCK_UNLOCKED; /* hardware lock */
+static struct timer_list rng_timer; /* kernel timer for RNG hardware reads and tests */
+static atomic_t rng_open;
+
+/*
+ * inlined helper functions for accessing RNG registers
+ */
+static inline u8 rng_hwstatus (void)
+{
+ assert (rng_mem != NULL);
+ return readb (rng_mem + RNG_HW_STATUS);
+}
+
+
+static inline void rng_hwstatus_set (u8 hw_status)
+{
+ assert (rng_mem != NULL);
+ writeb (hw_status, rng_mem + RNG_HW_STATUS);
+}
+
+
+static inline int rng_data_present (void)
+{
+ assert (rng_mem != NULL);
+ assert (rng_hw_enabled == 1);
+
+ return (readb (rng_mem + RNG_STATUS) & RNG_DATA_PRESENT) ? 1 : 0;
+}
+
+
+static inline int rng_data_read (void)
+{
+ assert (rng_mem != NULL);
+ assert (rng_hw_enabled == 1);
+
+ return readb (rng_mem + RNG_DATA);
+}
+
+
+/*
+ * rng_timer_ticker - executes every RNG_TIMER_LEN jiffies,
+ * adds a single byte to system entropy
+ * and internal FIPS test pools
+ */
+static void rng_timer_tick (unsigned long data)
+{
+ unsigned long flags;
+ int rng_data;
+
+ spin_lock_irqsave (&rng_lock, flags);
+
+ if (rng_data_present ()) {
+ /* gimme some thermal noise, baby */
+ rng_data = rng_data_read ();
+
+ /*
+ * if RNG has been verified in the past, add
+ * data just read to the /dev/random pool,
+ * with the entropy specified by the user
+ * via sysctl (defaults to 8 bits)
+ */
+ if (rng_trusted)
+ batch_entropy_store (rng_data, jiffies, rng_entropy);
+
+ /* fitness testing via FIPS, if we have enough data */
+ rng_fips_test_store (rng_data);
+ if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD)
+ rng_run_fips_test ();
+ }
+
+ spin_unlock_irqrestore (&rng_lock, flags);
+
+ /* run the timer again */
+ rng_timer.expires = jiffies + RNG_TIMER_LEN;
+ add_timer (&rng_timer);
+}
+
+
+/*
+ * rng_enable - enable or disable the RNG and internal timer
+ */
+static int rng_enable (int enable)
+{
+ unsigned long flags;
+ int rc = 0;
+ u8 hw_status;
+
+ DPRINTK ("ENTER\n");
+
+ spin_lock_irqsave (&rng_lock, flags);
+
+ hw_status = rng_hwstatus ();
+
+ if (enable && !rng_hw_enabled) {
+ rng_hwstatus_set (hw_status | RNG_ENABLED);
+
+ printk (KERN_INFO PFX "RNG h/w enabled\n");
+ rng_hw_enabled = 1;
+ MOD_INC_USE_COUNT;
+ }
+
+ else if (!enable && rng_hw_enabled) {
+ del_timer (&rng_timer);
+
+ rng_hwstatus_set (hw_status & ~RNG_ENABLED);
+
+ printk (KERN_INFO PFX "RNG h/w disabled\n");
+ rng_hw_enabled = 0;
+ MOD_DEC_USE_COUNT;
+ }
+
+ if (enable != (rng_hwstatus () & RNG_ENABLED) ) {
+ del_timer (&rng_timer);
+ printk (KERN_ERR PFX "Unable to %sable the RNG\n",
+ enable ? "en" : "dis");
+ rc = -EIO;
+ }
+
+ spin_unlock_irqrestore (&rng_lock, flags);
+
+ DPRINTK ("EXIT, returning %d\n", rc);
+ return rc;
+}
+
+
+/*
+ * rng_handle_sysctl_enable - handle a read or write of our enable/disable sysctl
+ */
+
+static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file *filp,
+ void *buffer, size_t * lenp)
+{
+ unsigned long flags;
+ int enabled_save, rc;
+
+ DPRINTK ("ENTER\n");
+
+ spin_lock_irqsave (&rng_lock, flags);
+ rng_enabled_sysctl = enabled_save = rng_hw_enabled;
+ spin_unlock_irqrestore (&rng_lock, flags);
+
+ rc = proc_dointvec (table, write, filp, buffer, lenp);
+ if (rc)
+ return rc;
+
+ if (enabled_save != rng_enabled_sysctl)
+ rng_enable (rng_enabled_sysctl);
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+/*
+ * rng_handle_sysctl_entropy - handle a read or write of our entropy bits sysctl
+ */
+
+static int rng_handle_sysctl_entropy (ctl_table * table, int write, struct file *filp,
+ void *buffer, size_t * lenp)
+{
+ unsigned long flags;
+ int entropy_bits_save, rc;
+
+ DPRINTK ("ENTER\n");
+
+ spin_lock_irqsave (&rng_lock, flags);
+ rng_entropy_sysctl = entropy_bits_save = rng_entropy;
+ spin_unlock_irqrestore (&rng_lock, flags);
+
+ rc = proc_dointvec (table, write, filp, buffer, lenp);
+ if (rc)
+ return rc;
+
+ if (entropy_bits_save == rng_entropy_sysctl)
+ goto out;
+
+ if ((rng_entropy_sysctl >= 0) &&
+ (rng_entropy_sysctl <= 8)) {
+ spin_lock_irqsave (&rng_lock, flags);
+ rng_entropy = rng_entropy_sysctl;
+ spin_unlock_irqrestore (&rng_lock, flags);
+
+ printk (KERN_INFO PFX "entropy bits now %d\n", rng_entropy_sysctl);
+ } else {
+ printk (KERN_INFO PFX "ignoring invalid entropy setting (%d)\n",
+ rng_entropy_sysctl);
+ }
+
+out:
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+/*
+ * rng_sysctl - add or remove the rng sysctl
+ */
+static void rng_sysctl (int add)
+{
+#define DEV_I810_RNG 1
+#define DEV_I810_RNG_ENTROPY 2
+ /* Definition of the sysctl */
+ static ctl_table rng_sysctls[] = {
+ {DEV_I810_RNG, /* ID */
+ RNG_MODULE_NAME "_enabled", /* name in /proc */
+ &rng_enabled_sysctl,
+ sizeof (rng_enabled_sysctl), /* data ptr, data size */
+ 0644, /* mode */
+ 0, /* child */
+ rng_handle_sysctl_enable, /* proc handler */
+ 0, /* strategy */
+ 0, /* proc control block */
+ 0, 0}
+ ,
+ {DEV_I810_RNG_ENTROPY, /* ID */
+ RNG_MODULE_NAME "_entropy", /* name in /proc */
+ &rng_entropy_sysctl,
+ sizeof (rng_entropy_sysctl), /* data ptr, data size */
+ 0644, /* mode */
+ 0, /* child */
+ rng_handle_sysctl_entropy, /* proc handler */
+ 0, /* strategy */
+ 0, /* proc control block */
+ 0, 0}
+ ,
+ {0}
+ };
+
+ /* Define the parent file : /proc/sys/dev */
+ static ctl_table sysctls_root[] = {
+ {CTL_DEV,
+ "dev",
+ NULL, 0,
+ 0555,
+ rng_sysctls},
+ {0}
+ };
+ static struct ctl_table_header *sysctls_root_header = NULL;
+
+ if (add) {
+ if (!sysctls_root_header)
+ sysctls_root_header = register_sysctl_table (sysctls_root, 0);
+ } else if (sysctls_root_header) {
+ unregister_sysctl_table (sysctls_root_header);
+ sysctls_root_header = NULL;
+ }
+}
+
+
+static int rng_dev_open (struct inode *inode, struct file *filp)
+{
+ int rc = -EINVAL;
+ unsigned long flags;
+
+ if ((filp->f_mode & FMODE_READ) == 0)
+ goto err_out;
+ if (filp->f_mode & FMODE_WRITE)
+ goto err_out;
+
+ spin_lock_irqsave (&rng_lock, flags);
+
+ if (atomic_read(&rng_open)) {
+ spin_unlock_irqrestore (&rng_lock, flags);
+ rc = -EBUSY;
+ goto err_out;
+ }
+
+ atomic_set (&rng_open, 1);
+
+ spin_unlock_irqrestore (&rng_lock, flags);
+
+ if (rng_enable(1) != 0) {
+ spin_lock_irqsave (&rng_lock, flags);
+ atomic_set (&rng_open, 0);
+ spin_unlock_irqrestore (&rng_lock, flags);
+ rc = -EIO;
+ goto err_out;
+ }
+
+ return 0;
+
+err_out:
+ return rc;
+}
+
+
+static int rng_dev_release (struct inode *inode, struct file *filp)
+{
+ unsigned long flags;
+
+ if (rng_enable(0) != 0)
+ return -EIO;
+
+ spin_lock_irqsave (&rng_lock, flags);
+ atomic_set (&rng_open, 0);
+ spin_unlock_irqrestore (&rng_lock, flags);
+
+ return 0;
+}
+
+
+static ssize_t rng_dev_read (struct file *filp, char * buf, size_t size,
+ loff_t *offp)
+{
+ int have_data, copied = 0;
+ unsigned long flags;
+ u8 data=0;
+ u8 *page;
+
+ if (size < 1)
+ return 0;
+
+ page = (unsigned char *) get_zeroed_page (GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+read_loop:
+ /* using the fact that read() can return >0 but
+ * less than the requested amount, we simply
+ * read up to PAGE_SIZE or buffer size, whichever
+ * is smaller, and return that data.
+ */
+ if ((copied == size) || (copied == PAGE_SIZE)) {
+ size_t tmpsize = (copied == size) ? size : PAGE_SIZE;
+ int rc = copy_to_user (buf, page, tmpsize);
+ free_page ((long)page);
+ if (rc) return rc;
+ return tmpsize;
+ }
+
+ spin_lock_irqsave (&rng_lock, flags);
+
+ have_data = 0;
+ if (rng_data_present ()) {
+ data = rng_data_read ();
+ have_data = 1;
+ }
+
+ spin_unlock_irqrestore (&rng_lock, flags);
+
+ if (have_data) {
+ page[copied] = data;
+ copied++;
+ } else {
+ if (filp->f_flags & O_NONBLOCK) {
+ free_page ((long)page);
+ return -EAGAIN;
+ }
+ }
+
+ if (current->need_resched)
+ schedule ();
+
+ if (signal_pending (current)) {
+ free_page ((long)page);
+ return -ERESTARTSYS;
+ }
+
+ goto read_loop;
+}
+
+
+/*
+ * rng_init_one - look for and attempt to init a single RNG
+ */
+static int __init rng_init_one (struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ int rc;
+ u8 hw_status;
+
+ DPRINTK ("ENTER\n");
+
+ if (rng_allocated) {
+ printk (KERN_ERR PFX "this driver only supports one RNG\n");
+ DPRINTK ("EXIT, returning -EBUSY\n");
+ return -EBUSY;
+ }
+
+ /* XXX currently fails, investigate who has our mem region */
+ if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME))
+ rng_have_mem_region = 1;
+
+ rng_mem = ioremap (RNG_ADDR, RNG_ADDR_LEN);
+ if (rng_mem == NULL) {
+ printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
+ DPRINTK ("EXIT, returning -EBUSY\n");
+ rc = -EBUSY;
+ goto err_out;
+ }
+
+ /* Check for Intel 82802 */
+ hw_status = rng_hwstatus ();
+ if ((hw_status & RNG_PRESENT) == 0) {
+ printk (KERN_ERR PFX "RNG not detected\n");
+ DPRINTK ("EXIT, returning -ENODEV\n");
+ rc = -ENODEV;
+ goto err_out;
+ }
+
+ rng_allocated = 1;
+
+ if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY)
+ rng_entropy = RNG_MAX_ENTROPY;
+
+ /* init core RNG timer, but do not add it */
+ init_timer (&rng_timer);
+ rng_timer.function = rng_timer_tick;
+
+ rc = rng_enable (0);
+ if (rc) {
+ printk (KERN_ERR PFX "cannot disable RNG, aborting\n");
+ goto err_out;
+ }
+
+ /* add sysctls */
+ rng_sysctl (1);
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+
+err_out:
+ if (rng_mem)
+ iounmap (rng_mem);
+ if (rng_have_mem_region)
+ release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
+ return rc;
+}
+
+
+/*
+ * Data for PCI driver interface
+ */
+const static struct pci_device_id rng_pci_tbl[] __initdata = {
+ { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, },
+ { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, },
+ { 0, },
+};
+MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
+
+static struct pci_driver rng_driver = {
+ name: RNG_MODULE_NAME,
+ id_table: rng_pci_tbl,
+ probe: rng_init_one,
+};
+
+MODULE_AUTHOR("Jeff Garzik, Matt Sottek");
+MODULE_DESCRIPTION("Intel i8xx chipset Random Number Generator (RNG) driver");
+MODULE_PARM(rng_entropy, "1i");
+MODULE_PARM_DESC(rng_entropy, "Bits of entropy to add to random pool per RNG byte (range: 0-8, default 8)");
+
+
+static struct file_operations rng_chrdev_ops = {
+ owner: THIS_MODULE,
+ open: rng_dev_open,
+ release: rng_dev_release,
+ read: rng_dev_read,
+};
+
+
+static struct miscdevice rng_miscdev = {
+ RNG_MISCDEV_MINOR,
+ RNG_MODULE_NAME,
+ &rng_chrdev_ops,
+};
+
+
+/*
+ * rng_init - initialize RNG module
+ */
+static int __init rng_init (void)
+{
+ int rc;
+
+ DPRINTK ("ENTER\n");
+
+ MOD_INC_USE_COUNT;
+
+ if (pci_register_driver (&rng_driver) < 1) {
+ DPRINTK ("EXIT, returning -ENODEV\n");
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
+
+ rc = misc_register (&rng_miscdev);
+ if (rc) {
+ pci_unregister_driver (&rng_driver);
+ DPRINTK ("EXIT, returning %d\n", rc);
+ MOD_DEC_USE_COUNT;
+ return rc;
+ }
+
+ printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
+
+ /* FIXME: verify module unload logic, then remove
+ * this additional MOD_INC_USE_COUNT */
+ MOD_INC_USE_COUNT;
+
+ MOD_DEC_USE_COUNT; /* init complete, unload allowed now */
+
+ DPRINTK ("EXIT, returning 0\n");
+ return 0;
+}
+
+
+/*
+ * rng_init - shutdown RNG module
+ */
+static void __exit rng_cleanup (void)
+{
+ unsigned long flags;
+
+ DPRINTK ("ENTER\n");
+
+ spin_lock_irqsave (&rng_lock, flags);
+ del_timer (&rng_timer);
+ spin_unlock_irqrestore (&rng_lock, flags);
+
+ rng_sysctl (0);
+ pci_unregister_driver (&rng_driver);
+
+ if (rng_have_mem_region)
+ release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
+
+ rng_hwstatus_set (rng_hwstatus() & ~RNG_ENABLED);
+
+ misc_deregister (&rng_miscdev);
+
+ DPRINTK ("EXIT\n");
+}
+
+
+module_init (rng_init);
+module_exit (rng_cleanup);
+
+
+
+
+/* These are the startup tests suggested by the FIPS 140-1 spec section
+* 4.11.1 (http://csrc.nist.gov/fips/fips1401.htm)
+* The Monobit, Poker, Runs, and Long Runs tests are implemented below.
+* This test is run at periodic intervals to verify
+* data is sufficently random. If the tests are failed the RNG module
+* will no longer submit data to the entropy pool, but the tests will
+* continue to run at the given interval. If at a later time the RNG
+* passes all tests it will be re-enabled for the next period.
+* The reason for this is that it is not unlikely that at some time
+* during normal operation one of the tests will fail. This does not
+* necessarily mean the RNG is not operating properly, it is just a
+* statistically rare event. In that case we don't want to forever
+* disable the RNG, we will just leave it disabled for the period of
+* time until the tests are rerun and passed.
+*
+* For argument sake I tested /proc/urandom with these tests and it
+* took 142,095 tries before I got a failure, and urandom isn't as
+* random as random :)
+*/
+
+static int poker[16] = { 0, }, runs[12] = { 0, };
+static int ones = 0, rlength = -1, current_bit = 0, rng_test = 0;
+
+
+/*
+ * rng_fips_test_store - store 8 bits of entropy in FIPS
+ * internal test data pool
+ */
+static void rng_fips_test_store (int rng_data)
+{
+ int j;
+ static int last_bit = 0;
+
+ DPRINTK ("ENTER, rng_data = %d\n", rng_data & 0xFF);
+
+ poker[rng_data >> 4]++;
+ poker[rng_data & 15]++;
+
+ /* Note in the loop below rlength is always one less than the actual
+ run length. This makes things easier. */
+ last_bit = (rng_data & 128) >> 7;
+ for (j = 7; j >= 0; j--) {
+ ones += current_bit = (rng_data & 1 << j) >> j;
+ if (current_bit != last_bit) {
+ /* If runlength is 1-6 count it in correct bucket. 0's go in
+ runs[0-5] 1's go in runs[6-11] hence the 6*current_bit below */
+ if (rlength < 5) {
+ runs[rlength +
+ (6 * current_bit)]++;
+ } else {
+ runs[5 + (6 * current_bit)]++;
+ }
+
+ /* Check if we just failed longrun test */
+ if (rlength >= 33)
+ rng_test &= 8;
+ rlength = 0;
+ /* flip the current run type */
+ last_bit = current_bit;
+ } else {
+ rlength++;
+ }
+ }
+
+ DPRINTK ("EXIT\n");
+}
+
+
+/*
+ * now that we have some data, run a FIPS test
+ */
+static void rng_run_fips_test (void)
+{
+ int j, i;
+
+ DPRINTK ("ENTER\n");
+
+ /* add in the last (possibly incomplete) run */
+ if (rlength < 5)
+ runs[rlength + (6 * current_bit)]++;
+ else {
+ runs[5 + (6 * current_bit)]++;
+ if (rlength >= 33)
+ rng_test &= 8;
+ }
+ /* Ones test */
+ if ((ones >= 10346) || (ones <= 9654))
+ rng_test &= 1;
+ /* Poker calcs */
+ for (i = 0, j = 0; i < 16; i++)
+ j += poker[i] * poker[i];
+ if ((j >= 1580457) || (j <= 1562821))
+ rng_test &= 2;
+ if ((runs[0] < 2267) || (runs[0] > 2733) ||
+ (runs[1] < 1079) || (runs[1] > 1421) ||
+ (runs[2] < 502) || (runs[2] > 748) ||
+ (runs[3] < 223) || (runs[3] > 402) ||
+ (runs[4] < 90) || (runs[4] > 223) ||
+ (runs[5] < 90) || (runs[5] > 223) ||
+ (runs[6] < 2267) || (runs[6] > 2733) ||
+ (runs[7] < 1079) || (runs[7] > 1421) ||
+ (runs[8] < 502) || (runs[8] > 748) ||
+ (runs[9] < 223) || (runs[9] > 402) ||
+ (runs[10] < 90) || (runs[10] > 223) ||
+ (runs[11] < 90) || (runs[11] > 223)) {
+ rng_test &= 4;
+ }
+
+ rng_test = !rng_test;
+ DPRINTK ("FIPS test %sed\n", rng_test ? "pass" : "fail");
+
+ /* enable/disable RNG with results of the tests */
+ if (rng_test && !rng_trusted)
+ printk (KERN_WARNING PFX "FIPS test passed, enabling RNG\n");
+ else if (!rng_test && rng_trusted)
+ printk (KERN_WARNING PFX "FIPS test failed, disabling RNG\n");
+
+ rng_trusted = rng_test;
+
+ /* finally, clear out FIPS variables for start of next run */
+ memset (&poker, 0, sizeof (poker));
+ memset (&runs, 0, sizeof (runs));
+ ones = 0;
+ rlength = -1;
+ current_bit = 0;
+ rng_test = 0;
+
+ DPRINTK ("EXIT\n");
+}
+
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index 6b42c7f63..033eb9aaf 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -311,6 +311,7 @@ static struct termios * TermiosLocked[IP2_MAX_PORTS];
* download the loadware to the boards.
*/
static struct file_operations ip2_ipl = {
+ owner: THIS_MODULE,
read: ip2_ipl_read,
write: ip2_ipl_write,
ioctl: ip2_ipl_ioctl,
@@ -3202,8 +3203,6 @@ ip2_ipl_open( struct inode *pInode, struct file *pFile )
printk (KERN_DEBUG "IP2IPL: open\n" );
#endif
- //MOD_INC_USE_COUNT; // Needs close entry with decrement.
-
switch(iplminor) {
// These are the IPL devices
case 0:
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 958fbf776..52c6b5f19 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -86,8 +86,6 @@ static char re_schedule = 1;
static unsigned long tx_count = 0;
#endif
-static int ISILoad_open(struct inode *inode, struct file *filp);
-static int ISILoad_release(struct inode *inode, struct file *filp);
static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
static void isicom_tx(unsigned long _data);
@@ -109,9 +107,8 @@ static signed char linuxb_to_isib[] = {
*/
static struct file_operations ISILoad_fops = {
+ owner: THIS_MODULE,
ioctl: ISILoad_ioctl,
- open: ISILoad_open,
- release: ISILoad_release,
};
struct miscdevice isiloader_device = {
@@ -129,24 +126,6 @@ extern inline int WaitTillCardIsFree(unsigned short base)
return 1;
}
-static int ISILoad_open(struct inode *inode, struct file *filp)
-{
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISILoad:Firmware loader Opened!!!\n");
-#endif
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-static int ISILoad_release(struct inode *inode, struct file *filp)
-{
-#ifdef ISICOM_DEBUG
- printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n",);
-#endif
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
static int ISILoad_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 5733fac43..8d16c9daf 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -687,8 +687,6 @@ static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *p
static int stli_brdinit(stlibrd_t *brdp);
static int stli_startbrd(stlibrd_t *brdp);
-static int stli_memopen(struct inode *ip, struct file *fp);
-static int stli_memclose(struct inode *ip, struct file *fp);
static ssize_t stli_memread(struct file *fp, char *buf, size_t count, loff_t *offp);
static ssize_t stli_memwrite(struct file *fp, const char *buf, size_t count, loff_t *offp);
static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
@@ -780,11 +778,10 @@ static inline int stli_initpcibrd(int brdtype, struct pci_dev *devp);
* board. This is also a very useful debugging tool.
*/
static struct file_operations stli_fsiomem = {
+ owner: THIS_MODULE,
read: stli_memread,
write: stli_memwrite,
ioctl: stli_memioctl,
- open: stli_memopen,
- release: stli_memclose,
};
/*****************************************************************************/
@@ -5183,27 +5180,6 @@ static int stli_getbrdstruct(unsigned long arg)
/*****************************************************************************/
/*
- * Memory device open code. Need to keep track of opens and close
- * for module handling.
- */
-
-static int stli_memopen(struct inode *ip, struct file *fp)
-{
- MOD_INC_USE_COUNT;
- return(0);
-}
-
-/*****************************************************************************/
-
-static int stli_memclose(struct inode *ip, struct file *fp)
-{
- MOD_DEC_USE_COUNT;
- return(0);
-}
-
-/*****************************************************************************/
-
-/*
* The "staliomem" device is also required to do some special operations on
* the board. We need to be able to send an interrupt to the board,
* reset it, and start/stop it.
diff --git a/drivers/char/joystick/joy-amiga.c b/drivers/char/joystick/joy-amiga.c
index 5e3198f70..8c0ba6923 100644
--- a/drivers/char/joystick/joy-amiga.c
+++ b/drivers/char/joystick/joy-amiga.c
@@ -78,26 +78,6 @@ static int js_am_read(void *info, int **axes, int **buttons)
}
/*
- * js_am_open() is a callback from the file open routine.
- */
-
-static int js_am_open(struct js_dev *jd)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * js_am_close() is a callback from the file release routine.
- */
-
-static int js_am_close(struct js_dev *jd)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
* js_am_init_corr() initializes correction values of
* Amiga joysticks.
*/
@@ -139,7 +119,7 @@ int __init js_am_init(void)
if (js_am[i]) {
js_am_port = js_register_port(js_am_port, &i, 1, sizeof(int), js_am_read);
printk(KERN_INFO "js%d: Amiga joystick at joy%ddat\n",
- js_register_device(js_am_port, 0, 2, 1, "Amiga joystick", js_am_open, js_am_close), i);
+ js_register_device(js_am_port, 0, 2, 1, "Amiga joystick", THIS_MODULE, NULL, NULL), i);
js_am_init_corr(js_am_port->corr);
}
if (js_am_port) return 0;
diff --git a/drivers/char/joystick/joy-analog.c b/drivers/char/joystick/joy-analog.c
index a4a7b9849..f73ee8ded 100644
--- a/drivers/char/joystick/joy-analog.c
+++ b/drivers/char/joystick/joy-analog.c
@@ -153,26 +153,6 @@ static int js_an_read(void *xinfo, int **axes, int **buttons)
}
/*
- * js_an_open() is a callback from the file open routine.
- */
-
-static int js_an_open(struct js_dev *jd)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * js_an_close() is a callback from the file release routine.
- */
-
-static int js_an_close(struct js_dev *jd)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
* js_an_calibrate_timer() calibrates the timer and computes loop
* and timeout values for a joystick port.
*/
@@ -248,7 +228,7 @@ static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct j
for (i = 0; i < numdev; i++)
printk(KERN_INFO "js%d: %s at %#x ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n",
js_register_device(port, i, js_an_axes(i, &ax->an), js_an_buttons(i, &ax->an),
- js_an_name(i, &ax->an), js_an_open, js_an_close),
+ js_an_name(i, &ax->an), THIS_MODULE, NULL, NULL),
js_an_name(i, &ax->an),
ax->io,
ax->speed > 10000 ? (ax->speed + 800) / 1000 : ax->speed,
diff --git a/drivers/char/joystick/joy-assassin.c b/drivers/char/joystick/joy-assassin.c
index b76ba8e36..469c6c8ce 100644
--- a/drivers/char/joystick/joy-assassin.c
+++ b/drivers/char/joystick/joy-assassin.c
@@ -177,26 +177,6 @@ static int js_as_read(void *xinfo, int **axes, int **buttons)
}
/*
- * js_as_open() is a callback from the file open routine.
- */
-
-static int js_as_open(struct js_dev *jd)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * js_as_close() is a callback from the file release routine.
- */
-
-static int js_as_close(struct js_dev *jd)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
* js_as_pxl_init_corr() initializes the correction values for
* the Panther XL.
*/
@@ -317,13 +297,13 @@ static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct j
if (info->mode == JS_AS_MODE_PXL) {
printk(KERN_INFO "js%d: MadCatz Panther XL at %#x\n",
- js_register_device(port, 0, 9, 9, "MadCatz Panther XL", js_as_open, js_as_close),
+ js_register_device(port, 0, 9, 9, "MadCatz Panther XL", THIS_MODULE, NULL, NULL),
info->io);
js_as_read(port->info, port->axes, port->buttons);
js_as_pxl_init_corr(port->corr, port->axes);
if (info->an.axes[0] < 254) {
printk(KERN_INFO "js%d: Analog rudder on MadCatz Panther XL\n",
- js_register_device(port, 1, 1, 0, "Analog rudder", js_as_open, js_as_close));
+ js_register_device(port, 1, 1, 0, "Analog rudder", THIS_MODULE, NULL, NULL));
info->rudder = 1;
port->axes[1][0] = info->an.axes[0];
js_as_rudder_init_corr(port->corr, port->axes);
@@ -339,7 +319,7 @@ static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct j
}
printk(KERN_INFO "js%d: %s at %#x\n",
- js_register_device(port, 0, 2, 3, name, js_as_open, js_as_close),
+ js_register_device(port, 0, 2, 3, name, THIS_MODULE, NULL, NULL),
name, info->io);
js_as_as_init_corr(port->corr);
@@ -354,7 +334,7 @@ static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct j
for (i = 0; i < numdev; i++)
printk(KERN_INFO "js%d: %s on %s\n",
js_register_device(port, i + 1, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
- js_an_name(i, &info->an), js_as_open, js_as_close),
+ js_an_name(i, &info->an), THIS_MODULE, NULL, NULL),
js_an_name(i, &info->an), name);
js_an_decode(&info->an, port->axes + 1, port->buttons + 1);
diff --git a/drivers/char/joystick/joy-console.c b/drivers/char/joystick/joy-console.c
index 58392f839..e56da540a 100644
--- a/drivers/char/joystick/joy-console.c
+++ b/drivers/char/joystick/joy-console.c
@@ -501,6 +501,7 @@ static int js_console_read(void *xinfo, int **axes, int **buttons)
/*
* open callback: claim parport.
+ * FIXME: if parport_claim() will sleep we can get into mess.
*/
int js_console_open(struct js_dev *dev)
@@ -754,7 +755,7 @@ static struct js_port __init *js_console_probe(int *config, struct js_port *port
for (i = 0; i < info.pads; i++) {
printk(KERN_INFO "js%d: %s on %s\n",
- js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close),
+ js_register_device(port, i, axes[i], buttons[i], name[i], NULL, js_console_open, js_console_close),
name[i], info.port->port->name);
js_console_init_corr(axes[i], type[i], port->corr[i]);
diff --git a/drivers/char/joystick/joy-creative.c b/drivers/char/joystick/joy-creative.c
index 8faec5f82..b5ae4c019 100644
--- a/drivers/char/joystick/joy-creative.c
+++ b/drivers/char/joystick/joy-creative.c
@@ -151,26 +151,6 @@ static int js_cr_read(void *xinfo, int **axes, int **buttons)
}
/*
- * js_cr_open() is a callback from the file open routine.
- */
-
-static int js_cr_open(struct js_dev *jd)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * js_cr_close() is a callback from the file release routine.
- */
-
-static int js_cr_close(struct js_dev *jd)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
* js_cr_init_corr() initializes correction values of
* Blaster gamepads.
*/
@@ -243,7 +223,7 @@ static struct js_port __init *js_cr_probe(int io, struct js_port *port)
if (info.mode[i]) {
printk(KERN_INFO "js%d: %s at %#x\n",
js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]],
- names[info.mode[i]], js_cr_open, js_cr_close),
+ names[info.mode[i]], THIS_MODULE, NULL, NULL),
names[info.mode[i]], io);
js_cr_init_corr(info.mode[i], port->corr[i]);
}
diff --git a/drivers/char/joystick/joy-db9.c b/drivers/char/joystick/joy-db9.c
index d5b6565ee..41169b12c 100644
--- a/drivers/char/joystick/joy-db9.c
+++ b/drivers/char/joystick/joy-db9.c
@@ -244,6 +244,7 @@ static int js_db9_read(void *xinfo, int **axes, int **buttons)
/*
* open callback: claim parport.
+ * FIXME: race possible.
*/
int js_db9_open(struct js_dev *dev)
@@ -364,7 +365,7 @@ static struct js_port __init *js_db9_probe(int *config, struct js_port *port)
for (i = 0; i < 1 + (info.mode == JS_MULTI_0802_2); i++) {
printk(KERN_INFO "js%d: %s on %s\n",
- js_register_device(port, i, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close),
+ js_register_device(port, i, 2, buttons[info.mode], name[info.mode], NULL, js_db9_open, js_db9_close),
name[info.mode], info.port->port->name);
js_db9_init_corr(port->corr[i]);
diff --git a/drivers/char/joystick/joy-gravis.c b/drivers/char/joystick/joy-gravis.c
index 3863d161f..84a6def16 100644
--- a/drivers/char/joystick/joy-gravis.c
+++ b/drivers/char/joystick/joy-gravis.c
@@ -231,26 +231,6 @@ static int js_gr_read(void *xinfo, int **axes, int **buttons)
}
/*
- * js_gr_open() is a callback from the file open routine.
- */
-
-static int js_gr_open(struct js_dev *jd)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * js_gr_close() is a callback from the file release routine.
- */
-
-static int js_gr_close(struct js_dev *jd)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
* js_gr_init_corr() initializes correction values of
* GrIP joysticks.
*/
@@ -359,7 +339,7 @@ static struct js_port __init *js_gr_probe(int io, struct js_port *port)
if (info.mode[i]) {
printk(KERN_INFO "js%d: %s at %#x\n",
js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]],
- names[info.mode[i]], js_gr_open, js_gr_close),
+ names[info.mode[i]], THIS_MODULE, NULL, NULL),
names[info.mode[i]], io);
js_gr_init_corr(info.mode[i], port->corr[i]);
}
diff --git a/drivers/char/joystick/joy-lightning.c b/drivers/char/joystick/joy-lightning.c
index 038d33a3c..26c18856a 100644
--- a/drivers/char/joystick/joy-lightning.c
+++ b/drivers/char/joystick/joy-lightning.c
@@ -208,26 +208,6 @@ static void js_l4_calibrate(struct js_l4_info *info)
js_l4_setcal(info->port, cal);
}
-
-/*
- * js_l4_open() is a callback from the file open routine.
- */
-
-static int js_l4_open(struct js_dev *jd)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * js_l4_close() is a callback from the file release routine.
- */
-
-static int js_l4_close(struct js_dev *jd)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
/*
* js_l4_probe() probes for joysticks on the L4 cards.
@@ -262,7 +242,7 @@ static struct js_port __init *js_l4_probe(unsigned char *cards, int l4port, int
for (i = 0; i < numdev; i++)
printk(KERN_INFO "js%d: %s on L4 port %d\n",
js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
- js_an_name(i, &info->an), js_l4_open, js_l4_close),
+ js_an_name(i, &info->an), THIS_MODULE, NULL, NULL),
js_an_name(i, &info->an), info->port);
js_l4_calibrate(info);
diff --git a/drivers/char/joystick/joy-logitech.c b/drivers/char/joystick/joy-logitech.c
index daea89c8b..6044cbfb0 100644
--- a/drivers/char/joystick/joy-logitech.c
+++ b/drivers/char/joystick/joy-logitech.c
@@ -276,26 +276,6 @@ static int js_lt_read(void *xinfo, int **axes, int **buttons)
}
/*
- * js_lt_open() is a callback from the file open routine.
- */
-
-static int js_lt_open(struct js_dev *jd)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * js_lt_close() is a callback from the file release routine.
- */
-
-static int js_lt_close(struct js_dev *jd)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
* js_lt_init_digital() sends a trigger & delay sequence
* to reset and initialize a Logitech joystick into digital mode.
*/
@@ -482,7 +462,7 @@ static struct js_port __init *js_lt_probe(int io, struct js_port *port)
printk(KERN_INFO "js%d: %s [%s] at %#x\n",
js_register_device(port, i,
info->axes10[i] + info->axes8[i] + ((info->hats[i] + (info->pad[i] >= 0)) << 1),
- info->buttons[i], name, js_lt_open, js_lt_close), name, info->name[i], io);
+ info->buttons[i], name, THIS_MODULE, NULL, NULL), name, info->name[i], io);
}
mdelay(JS_LT_INIT_DELAY);
diff --git a/drivers/char/joystick/joy-magellan.c b/drivers/char/joystick/joy-magellan.c
index 3a54d157e..cb14646e8 100644
--- a/drivers/char/joystick/joy-magellan.c
+++ b/drivers/char/joystick/joy-magellan.c
@@ -232,7 +232,6 @@ static int js_mag_open(struct js_dev *jd)
{
struct js_mag_info *info = jd->port->info;
info->used++;
- MOD_INC_USE_COUNT;
return 0;
}
@@ -247,7 +246,6 @@ static int js_mag_close(struct js_dev *jd)
js_unregister_device(jd->port->devs[0]);
js_mag_port = js_unregister_port(jd->port);
}
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -298,7 +296,7 @@ static int js_mag_ldisc_open(struct tty_struct *tty)
}
printk(KERN_INFO "js%d: Magellan [%s] on %s%d\n",
- js_register_device(js_mag_port, 0, 6, 9, "Magellan", js_mag_open, js_mag_close),
+ js_register_device(js_mag_port, 0, 6, 9, "Magellan", THIS_MODULE, js_mag_open, js_mag_close),
info->name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
diff --git a/drivers/char/joystick/joy-pci.c b/drivers/char/joystick/joy-pci.c
index ae49fd8e1..fbf9125e5 100644
--- a/drivers/char/joystick/joy-pci.c
+++ b/drivers/char/joystick/joy-pci.c
@@ -150,26 +150,6 @@ static int js_pci_read(void *xinfo, int **axes, int **buttons)
return 0;
}
-
-/*
- * js_pci_open() is a callback from the file open routine.
- */
-
-static int js_pci_open(struct js_dev *jd)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * js_pci_close() is a callback from the file release routine.
- */
-
-static int js_pci_close(struct js_dev *jd)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
static struct js_port * __init js_pci_probe(struct js_port *port, int type, int number,
struct pci_dev *pci_p, struct js_pci_data *data)
@@ -212,7 +192,7 @@ static struct js_port * __init js_pci_probe(struct js_port *port, int type, int
for (i = 0; i < numdev; i++)
printk(KERN_WARNING "js%d: %s on %s #%d\n",
js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
- js_an_name(i, &info->an), js_pci_open, js_pci_close), js_an_name(i, &info->an), data->name, number);
+ js_an_name(i, &info->an), THIS_MODULE, NULL, NULL), js_an_name(i, &info->an), data->name, number);
js_pci_read(info, port->axes, port->buttons);
js_an_init_corr(&info->an, port->axes, port->corr, 32);
@@ -243,7 +223,8 @@ int __init js_pci_init(void)
for (i = 0; js_pci_data[i].vendor; i++)
for (j = 0; (pci_p = pci_find_device(js_pci_data[i].vendor, js_pci_data[i].model, pci_p)); j++)
- js_pci_port = js_pci_probe(js_pci_port, i, j, pci_p, js_pci_data + i);
+ if (pci_enable_device(pci_p) == 0)
+ js_pci_port = js_pci_probe(js_pci_port, i, j, pci_p, js_pci_data + i);
if (!js_pci_port) {
#ifdef MODULE
diff --git a/drivers/char/joystick/joy-sidewinder.c b/drivers/char/joystick/joy-sidewinder.c
index 37d276ba1..da11598f4 100644
--- a/drivers/char/joystick/joy-sidewinder.c
+++ b/drivers/char/joystick/joy-sidewinder.c
@@ -476,26 +476,6 @@ static int js_sw_read(void *xinfo, int **axes, int **buttons)
}
/*
- * js_sw_open() is a callback from the file open routine.
- */
-
-static int js_sw_open(struct js_dev *jd)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * js_sw_close() is a callback from the file release routine.
- */
-
-static int js_sw_close(struct js_dev *jd)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
* js_sw_init_corr() initializes the correction values for
* SideWinders.
*/
@@ -810,7 +790,7 @@ static struct js_port __init *js_sw_probe(int io, struct js_port *port)
for (i = 0; i < info.number; i++)
printk(KERN_INFO "js%d: %s%s at %#x [%d ns res %d-bit id %d data %d]\n",
js_register_device(port, i, axes[info.type], buttons[info.type],
- names[info.type], js_sw_open, js_sw_close), names[info.type], comment, io,
+ names[info.type], THIS_MODULE, NULL, NULL), names[info.type], comment, io,
1000000 / speed, m, j, k);
js_sw_init_corr(axes[info.type], info.type, info.number, port->corr);
diff --git a/drivers/char/joystick/joy-spaceball.c b/drivers/char/joystick/joy-spaceball.c
index 874eb5268..3ace13642 100644
--- a/drivers/char/joystick/joy-spaceball.c
+++ b/drivers/char/joystick/joy-spaceball.c
@@ -152,7 +152,6 @@ static int js_sball_open(struct js_dev *jd)
{
struct js_sball_info *info = jd->port->info;
info->used++;
- MOD_INC_USE_COUNT;
return 0;
}
@@ -167,7 +166,6 @@ static int js_sball_close(struct js_dev *jd)
js_unregister_device(jd->port->devs[0]);
js_sball_port = js_unregister_port(jd->port);
}
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -219,7 +217,7 @@ static int js_sball_ldisc_open(struct tty_struct *tty)
info->port = js_sball_port;
tty->disc_data = info;
- info->js = js_register_device(js_sball_port, 0, 6, 12, "SpaceBall 4000 FLX", js_sball_open, js_sball_close);
+ info->js = js_register_device(js_sball_port, 0, 6, 12, "SpaceBall 4000 FLX", THIS_MODULE, js_sball_open, js_sball_close);
js_sball_init_corr(js_sball_port->corr);
diff --git a/drivers/char/joystick/joy-spaceorb.c b/drivers/char/joystick/joy-spaceorb.c
index a154bcdd5..0fb4f4c71 100644
--- a/drivers/char/joystick/joy-spaceorb.c
+++ b/drivers/char/joystick/joy-spaceorb.c
@@ -152,7 +152,6 @@ static int js_orb_open(struct js_dev *jd)
{
struct js_orb_info *info = jd->port->info;
info->used++;
- MOD_INC_USE_COUNT;
return 0;
}
@@ -167,7 +166,6 @@ static int js_orb_close(struct js_dev *jd)
js_unregister_device(jd->port->devs[0]);
js_orb_port = js_unregister_port(jd->port);
}
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -211,7 +209,7 @@ static int js_orb_ldisc_open(struct tty_struct *tty)
info->port = js_orb_port;
tty->disc_data = info;
- info->js = js_register_device(js_orb_port, 0, 6, 7, "SpaceOrb 360", js_orb_open, js_orb_close);
+ info->js = js_register_device(js_orb_port, 0, 6, 7, "SpaceOrb 360", THIS_MODULE, js_orb_open, js_orb_close);
js_orb_init_corr(js_orb_port->corr);
diff --git a/drivers/char/joystick/joy-thrustmaster.c b/drivers/char/joystick/joy-thrustmaster.c
index 4cd3de23f..56e043a59 100644
--- a/drivers/char/joystick/joy-thrustmaster.c
+++ b/drivers/char/joystick/joy-thrustmaster.c
@@ -163,26 +163,6 @@ static int js_tm_read(void *xinfo, int **axes, int **buttons)
}
/*
- * js_tm_open() is a callback from the file open routine.
- */
-
-static int js_tm_open(struct js_dev *jd)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * js_tm_close() is a callback from the file release routine.
- */
-
-static int js_tm_close(struct js_dev *jd)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-/*
* js_tm_init_corr() initializes the correction values for
* ThrustMaster joysticks.
*/
@@ -261,7 +241,7 @@ static struct js_port __init *js_tm_probe(int io, struct js_port *port)
request_region(io, 1, "joystick (thrustmaster)");
port = js_register_port(port, &info, 1, sizeof(struct js_tm_info), js_tm_read);
printk(KERN_INFO "js%d: %s revision %d at %#x\n",
- js_register_device(port, 0, a, b, name, js_tm_open, js_tm_close), name, data[JS_TM_BYTE_REV], io);
+ js_register_device(port, 0, a, b, name, THIS_MODULE, NULL, NULL), name, data[JS_TM_BYTE_REV], io);
js_tm_init_corr(a, info.mode, port->axes, port->corr);
return port;
diff --git a/drivers/char/joystick/joy-turbografx.c b/drivers/char/joystick/joy-turbografx.c
index 0211ea6f9..c138a99d0 100644
--- a/drivers/char/joystick/joy-turbografx.c
+++ b/drivers/char/joystick/joy-turbografx.c
@@ -101,6 +101,7 @@ static int js_tg_read(void *xinfo, int **axes, int **buttons)
/*
* open callback: claim parport.
+ * FIXME: race possible here.
*/
int js_tg_open(struct js_dev *dev)
@@ -205,7 +206,7 @@ static struct js_port __init *js_tg_probe(int *config, struct js_port *port)
for (i = 0; i < 7; i++)
if (config[i+1] > 0 && config[i+1] < 6) {
printk(KERN_INFO "js%d: Multisystem joystick on %s\n",
- js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close),
+ js_register_device(port, i, 2, config[i+1], "Multisystem joystick", NULL, js_tg_open, js_tg_close),
info->port->port->name);
info->sticks |= (1 << i);
}
diff --git a/drivers/char/joystick/joy-warrior.c b/drivers/char/joystick/joy-warrior.c
index 8737d1cc9..232699859 100644
--- a/drivers/char/joystick/joy-warrior.c
+++ b/drivers/char/joystick/joy-warrior.c
@@ -123,7 +123,6 @@ static int js_war_open(struct js_dev *jd)
{
struct js_war_info *info = jd->port->info;
info->used++;
- MOD_INC_USE_COUNT;
return 0;
}
@@ -138,7 +137,6 @@ static int js_war_close(struct js_dev *jd)
js_unregister_device(jd->port->devs[0]);
js_war_port = js_unregister_port(jd->port);
}
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -200,7 +198,7 @@ static int js_war_ldisc_open(struct tty_struct *tty)
tty->disc_data = info;
printk(KERN_INFO "js%d: WingMan Warrior on %s%d\n",
- js_register_device(js_war_port, 0, 6, 4, "WingMan Warrior", js_war_open, js_war_close),
+ js_register_device(js_war_port, 0, 6, 4, "WingMan Warrior", THIS_MODULE, js_war_open, js_war_close),
tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
js_war_init_corr(js_war_port->corr);
diff --git a/drivers/char/joystick/joystick.c b/drivers/char/joystick/joystick.c
index 1b156538e..c9bd56ce3 100644
--- a/drivers/char/joystick/joystick.c
+++ b/drivers/char/joystick/joystick.c
@@ -511,15 +511,21 @@ static int js_open(struct inode *inode, struct file *file)
if (!jd) return -ENODEV;
- if ((result = jd->open(jd)))
+ if (jd->owner)
+ __MOD_INC_USE_COUNT(jd->owner);
+ if (jd->open && (result = jd->open(jd))) {
+ if (jd->owner)
+ __MOD_DEC_USE_COUNT(jd->owner);
return result;
-
- MOD_INC_USE_COUNT;
+ }
new = kmalloc(sizeof(struct js_list), GFP_KERNEL);
if (!new) {
- jd->close(jd);
- MOD_DEC_USE_COUNT;
+ if (jd->close)
+ jd->close(jd);
+ if (jd->owner)
+ __MOD_DEC_USE_COUNT(jd->owner);
+
return -ENOMEM;
}
@@ -577,9 +583,10 @@ static int js_release(struct inode *inode, struct file *file)
if (!--js_use_count) del_timer(&js_timer);
- jd->close(jd);
-
- MOD_DEC_USE_COUNT;
+ if (jd->close)
+ jd->close(jd);
+ if (jd->owner)
+ __MOD_DEC_USE_COUNT(jd->owner);
return 0;
}
@@ -659,8 +666,9 @@ extern struct file_operations js_fops;
static devfs_handle_t devfs_handle = NULL;
-int js_register_device(struct js_port *port, int number, int axes, int buttons, char *name,
- js_ops_func open, js_ops_func close)
+int js_register_device(struct js_port *port, int number, int axes,
+ int buttons, char *name, struct module *owner,
+ js_ops_func open, js_ops_func close)
{
struct js_dev **ptrd = &js_dev;
struct js_dev *curd;
@@ -681,6 +689,7 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons,
curd->port = port;
curd->open = open;
curd->close = close;
+ curd->owner = owner;
init_waitqueue_head(&curd->wait);
@@ -743,6 +752,7 @@ void js_unregister_device(struct js_dev *dev)
static struct file_operations js_fops =
{
+ owner: THIS_MODULE,
read: js_read,
poll: js_poll,
ioctl: js_ioctl,
diff --git a/drivers/char/logibusmouse.c b/drivers/char/logibusmouse.c
index f9eae25eb..5e9ef9360 100644
--- a/drivers/char/logibusmouse.c
+++ b/drivers/char/logibusmouse.c
@@ -107,7 +107,6 @@ static int close_mouse(struct inode * inode, struct file * file)
{
MSE_INT_OFF();
free_irq(mouse_irq, NULL);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -119,13 +118,12 @@ static int open_mouse(struct inode * inode, struct file * file)
{
if (request_irq(mouse_irq, mouse_interrupt, 0, "busmouse", NULL))
return -EBUSY;
- MOD_INC_USE_COUNT;
MSE_INT_ON();
return 0;
}
static struct busmouse busmouse = {
- LOGITECH_BUSMOUSE, "busmouse", open_mouse, close_mouse, 7
+ LOGITECH_BUSMOUSE, "busmouse", THIS_MODULE, open_mouse, close_mouse, 7
};
static int __init logi_busmouse_init(void)
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 90f034396..c2df7ea18 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -371,8 +371,6 @@ static int lp_open(struct inode * inode, struct file * file)
if (test_and_set_bit(LP_BUSY_BIT_POS, &LP_F(minor)))
return -EBUSY;
- MOD_INC_USE_COUNT;
-
/* If ABORTOPEN is set and the printer is offline or out of paper,
we may still want to open it to perform ioctl()s. Therefore we
have commandeered O_NONBLOCK, even though it is being used in
@@ -385,24 +383,20 @@ static int lp_open(struct inode * inode, struct file * file)
parport_release (lp_table[minor].dev);
if (status & LP_POUTPA) {
printk(KERN_INFO "lp%d out of paper\n", minor);
- MOD_DEC_USE_COUNT;
LP_F(minor) &= ~LP_BUSY;
return -ENOSPC;
} else if (!(status & LP_PSELECD)) {
printk(KERN_INFO "lp%d off-line\n", minor);
- MOD_DEC_USE_COUNT;
LP_F(minor) &= ~LP_BUSY;
return -EIO;
} else if (!(status & LP_PERRORP)) {
printk(KERN_ERR "lp%d printer error\n", minor);
- MOD_DEC_USE_COUNT;
LP_F(minor) &= ~LP_BUSY;
return -EIO;
}
}
lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL);
if (!lp_table[minor].lp_buffer) {
- MOD_DEC_USE_COUNT;
LP_F(minor) &= ~LP_BUSY;
return -ENOMEM;
}
@@ -415,7 +409,6 @@ static int lp_release(struct inode * inode, struct file * file)
kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
lp_table[minor].lp_buffer = NULL;
- MOD_DEC_USE_COUNT;
LP_F(minor) &= ~LP_BUSY;
return 0;
}
@@ -526,6 +519,7 @@ static int lp_ioctl(struct inode *inode, struct file *file,
}
static struct file_operations lp_fops = {
+ owner: THIS_MODULE,
write: lp_write,
ioctl: lp_ioctl,
open: lp_open,
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 86ee11a5e..df1e97494 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -112,8 +112,7 @@ static int misc_open(struct inode * inode, struct file * file)
int minor = MINOR(inode->i_rdev);
struct miscdevice *c;
int err = -ENODEV;
-
- file->f_op = NULL;
+ struct file_operations *old_fops;
down(&misc_sem);
@@ -134,14 +133,22 @@ static int misc_open(struct inode * inode, struct file * file)
goto fail;
}
- if ((file->f_op = c->fops) && file->f_op->open)
+ old_fops = file->f_op;
+ file->f_op = fops_get(c->fops);
+ if (file->f_op && file->f_op->open)
err=file->f_op->open(inode,file);
+ if (err) {
+ fops_put(file->f_op);
+ file->f_op = fops_get(old_fops);
+ }
+ fops_put(old_fops);
fail:
up(&misc_sem);
return err;
}
static struct file_operations misc_fops = {
+ owner: THIS_MODULE,
open: misc_open,
};
diff --git a/drivers/char/mixcomwd.c b/drivers/char/mixcomwd.c
index 5894353e3..6352d6f73 100644
--- a/drivers/char/mixcomwd.c
+++ b/drivers/char/mixcomwd.c
@@ -94,8 +94,6 @@ static int mixcomwd_open(struct inode *inode, struct file *file)
mixcomwd_timer_alive=0;
}
#endif
- MOD_INC_USE_COUNT;
-
return 0;
}
@@ -114,7 +112,6 @@ static int mixcomwd_release(struct inode *inode, struct file *file)
mixcomwd_timer_alive=1;
add_timer(&mixcomwd_timer);
#endif
- MOD_DEC_USE_COUNT;
clear_bit(0,&mixcomwd_opened);
return 0;
@@ -171,6 +168,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
static struct file_operations mixcomwd_fops=
{
+ owner: THIS_MODULE,
write: mixcomwd_write,
ioctl: mixcomwd_ioctl,
open: mixcomwd_open,
diff --git a/drivers/char/msbusmouse.c b/drivers/char/msbusmouse.c
index c3148a9cc..e47817fae 100644
--- a/drivers/char/msbusmouse.c
+++ b/drivers/char/msbusmouse.c
@@ -108,7 +108,6 @@ static int release_mouse(struct inode * inode, struct file * file)
{
MS_MSE_INT_OFF();
free_irq(mouse_irq, NULL);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -118,13 +117,12 @@ static int open_mouse(struct inode * inode, struct file * file)
return -EBUSY;
outb(MS_MSE_START, MS_MSE_CONTROL_PORT);
- MOD_INC_USE_COUNT;
MS_MSE_INT_ON();
return 0;
}
static struct busmouse msbusmouse = {
- MICROSOFT_BUSMOUSE, "msbusmouse", open_mouse, release_mouse, 0
+ MICROSOFT_BUSMOUSE, "msbusmouse", THIS_MODULE, open_mouse, release_mouse, 0
};
static int __init ms_bus_mouse_init(void)
diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c
index f4252a071..d6fa8314b 100644
--- a/drivers/char/msp3400.c
+++ b/drivers/char/msp3400.c
@@ -1,7 +1,7 @@
/*
* programming the msp34* sound processor family
*
- * (c) 1997,1998 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ * (c) 1997-2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
*
* what works and what doesn't:
*
@@ -46,6 +46,7 @@
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <asm/semaphore.h>
+#include <linux/init.h>
#ifdef CONFIG_SMP
#include <asm/pgtable.h>
@@ -57,16 +58,14 @@
#include "audiochip.h"
-#define WAIT_QUEUE wait_queue_head_t
-
/* sound mixer stuff */
-#if defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE)
+#if 0 /* defined(CONFIG_SOUND) || defined(CONFIG_SOUND_MODULE) */
# define REGISTER_MIXER 1
#endif
/* Addresses to scan */
static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {0x40,0x44,I2C_CLIENT_END};
+static unsigned short normal_i2c_range[] = {0x40,0x40,I2C_CLIENT_END};
static unsigned short probe[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
static unsigned short probe_range[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
static unsigned short ignore[2] = { I2C_CLIENT_END, I2C_CLIENT_END };
@@ -102,7 +101,7 @@ struct msp3400c {
/* thread */
struct task_struct *thread;
- WAIT_QUEUE wq;
+ wait_queue_head_t wq;
struct semaphore *notify;
int active,restart,rmmod;
@@ -680,10 +679,10 @@ static int msp3400c_thread(void *data)
#endif
exit_mm(current);
+ exit_fs(current);
current->session = 1;
current->pgrp = 1;
sigfillset(&current->blocked);
- current->fs->umask = 0;
strcpy(current->comm,"msp3400");
msp->thread = current;
@@ -932,10 +931,10 @@ static int msp3410d_thread(void *data)
#endif
exit_mm(current);
+ exit_fs(current);
current->session = 1;
current->pgrp = 1;
sigfillset(&current->blocked);
- current->fs->umask = 0;
strcpy(current->comm,"msp3410 [auto]");
msp->thread = current;
@@ -1256,7 +1255,6 @@ msp3400c_mixer_open(struct inode *inode, struct file *file)
if (client->adapter->inc_use)
client->adapter->inc_use(client->adapter);
- MOD_INC_USE_COUNT;
return 0;
}
@@ -1267,7 +1265,6 @@ msp3400c_mixer_release(struct inode *inode, struct file *file)
if (client->adapter->dec_use)
client->adapter->dec_use(client->adapter);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -1278,6 +1275,7 @@ msp3400c_mixer_llseek(struct file *file, loff_t offset, int origin)
}
static struct file_operations msp3400c_mixer_fops = {
+ owner: THIS_MODULE,
llseek: msp3400c_mixer_llseek,
ioctl: msp3400c_mixer_ioctl,
open: msp3400c_mixer_open,
@@ -1370,7 +1368,7 @@ static int msp_attach(struct i2c_adapter *adap, int addr,
if (simple == -1) {
/* default mode */
- msp->simple = 0;
+ msp->simple = (((rev2>>8)&0xff) == 0) ? 0 : 1;
} else {
/* use insmod option */
msp->simple = simple;
@@ -1632,22 +1630,19 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
/* ----------------------------------------------------------------------- */
-#ifdef MODULE
-int init_module(void)
-#else
-int msp3400c_init(void)
-#endif
+int msp3400_init_module(void)
{
i2c_add_driver(&driver);
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+void msp3400_cleanup_module(void)
{
i2c_del_driver(&driver);
}
-#endif
+
+module_init(msp3400_init_module);
+module_exit(msp3400_cleanup_module);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 8de8336d1..fbbec0fb1 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -618,6 +618,8 @@ int mxser_init(void)
mxser_pcibrds[b].device_id, pdev);
if (!pdev)
break;
+ if (pci_enable_device(pdev))
+ continue;
b++;
hwconf.pdev = pdev;
printk("Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 1d27b680d..7a0df755e 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -663,7 +663,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
#if LINUX_VERSION_CODE < VERSION(2,3,0)
kill_fasync (n_hdlc->tty->fasync, SIGIO);
#else
- kill_fasync (n_hdlc->tty->fasync, SIGIO, POLL_IN);
+ kill_fasync(&n_hdlc->tty->fasync, SIGIO, POLL_IN);
#endif
} /* end of n_hdlc_tty_receive() */
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 81d562747..f488d9124 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -630,8 +630,7 @@ send_signal:
put_tty_queue(c, tty);
tty->canon_head = tty->read_head;
tty->canon_data++;
- if (tty->fasync)
- kill_fasync(tty->fasync, SIGIO, POLL_IN);
+ kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
return;
@@ -735,8 +734,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
}
if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {
- if (tty->fasync)
- kill_fasync(tty->fasync, SIGIO, POLL_IN);
+ kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible(&tty->read_wait);
}
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index c5be675c7..42063cefa 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -332,7 +332,6 @@ static int nvram_open( struct inode *inode, struct file *file )
if (file->f_mode & 2)
nvram_open_mode |= NVRAM_WRITE;
nvram_open_cnt++;
- MOD_INC_USE_COUNT;
return( 0 );
}
@@ -344,7 +343,6 @@ static int nvram_release( struct inode *inode, struct file *file )
if (file->f_mode & 2)
nvram_open_mode &= ~NVRAM_WRITE;
- MOD_DEC_USE_COUNT;
return( 0 );
}
@@ -393,6 +391,7 @@ static int nvram_read_proc( char *buffer, char **start, off_t offset,
#endif /* CONFIG_PROC_FS */
static struct file_operations nvram_fops = {
+ owner: THIS_MODULE,
llseek: nvram_llseek,
read: nvram_read,
write: nvram_write,
diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c
index 34d996582..8cf8a15a7 100644
--- a/drivers/char/nwbutton.c
+++ b/drivers/char/nwbutton.c
@@ -172,34 +172,6 @@ static int button_read (struct file *filp, char *buffer,
? -EFAULT : bcount;
}
-/*
- * This function is called when a user space process attempts to open the
- * device. If the driver is compiled into the kernel it does nothing but
- * succeed, but if it is compiled in as a module it also increments the
- * module usage count to prevent the module from being removed whilst a
- * process has the device open.
- */
-
-static int button_open (struct inode *inode, struct file *filp)
-{
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * This function is called when a user space process attempts to close the
- * device. If the driver is compiled into the kernel it does nothing at all,
- * but if it is compiled in as a module it also decrements the module usage
- * count so that it will be possible to unload the module again once all the
- * user processes have closed the device.
- */
-
-static int button_release (struct inode *inode, struct file *filp)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
/*
* This structure is the file operations structure, which specifies what
* callbacks functions the kernel should call when a user mode process
@@ -207,9 +179,8 @@ static int button_release (struct inode *inode, struct file *filp)
*/
static struct file_operations button_fops = {
+ owner: THIS_MODULE,
read: button_read,
- open: button_open,
- release: button_release,
};
/*
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index 579e970d4..5be07b769 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -39,7 +39,6 @@ MSTATIC int get_flash_id(void);
MSTATIC int erase_block(int nBlock);
MSTATIC int write_block(unsigned long p, const char *buf, int count);
static int open_flash(struct inode *inodep, struct file *filep);
-static int release_flash(struct inode *inodep, struct file *filep);
static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg);
static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * ppos);
static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos);
@@ -60,12 +59,12 @@ extern spinlock_t gpio_lock;
static struct file_operations flash_fops =
{
+ owner: THIS_MODULE,
llseek: flash_llseek,
read: flash_read,
write: flash_write,
ioctl: flash_ioctl,
open: open_flash,
- release: release_flash,
};
static struct miscdevice flash_miscdev =
@@ -128,19 +127,10 @@ static int open_flash(struct inode *inodep, struct file *filep)
printk("Flash: incorrect ID 0x%04X.\n", id);
return -ENXIO;
}
- MOD_INC_USE_COUNT;
return 0;
}
-
-static int release_flash(struct inode *inodep, struct file *filep)
-{
- MOD_DEC_USE_COUNT;
- return 0;
-}
-
-
static int flash_ioctl(struct inode *inodep, struct file *filep, unsigned int cmd, unsigned long arg)
{
// printk("Flash_ioctl: cmd = 0x%X.\n",cmd);
diff --git a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c
index e0b620596..dfef66e39 100644
--- a/drivers/char/pc110pad.c
+++ b/drivers/char/pc110pad.c
@@ -83,8 +83,7 @@ static struct semaphore reader_lock;
static void wake_readers(void)
{
wake_up_interruptible(&queue);
- if(asyncptr)
- kill_fasync(asyncptr, SIGIO, POLL_IN);
+ kill_fasync(&asyncptr, SIGIO, POLL_IN);
}
@@ -588,7 +587,6 @@ static int close_pad(struct inode * inode, struct file * file)
if (--active)
return 0;
outb(0x30, current_params.io+2); /* switch off digitiser */
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -610,7 +608,6 @@ static int open_pad(struct inode * inode, struct file * file)
if (active++)
return 0;
- MOD_INC_USE_COUNT;
save_flags(flags);
cli();
@@ -772,6 +769,7 @@ static int pad_ioctl(struct inode *inode, struct file * file,
static struct file_operations pad_fops = {
+ owner: THIS_MODULE,
read: read_pad,
write: write_pad,
poll: pad_poll,
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index c8a1da0d3..86d012bed 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -415,8 +415,7 @@ static inline void handle_mouse_event(unsigned char scancode)
head = (head + 1) & (AUX_BUF_SIZE-1);
if (head != queue->tail) {
queue->head = head;
- if (queue->fasync)
- kill_fasync(queue->fasync, SIGIO, POLL_IN);
+ kill_fasync(&queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
}
}
@@ -452,7 +451,9 @@ static unsigned char handle_kbd_event(void)
scancode = kbd_read_input();
-#if 0
+ /* Error bytes must be ignored to make the
+ Synaptics touchpads compaq use work */
+#if 1
/* Ignore error bytes */
if (!(status & (KBD_STAT_GTO | KBD_STAT_PERR)))
#endif
diff --git a/drivers/char/pcmcia/serial_cb.c b/drivers/char/pcmcia/serial_cb.c
index 457b2f647..86bb70f57 100644
--- a/drivers/char/pcmcia/serial_cb.c
+++ b/drivers/char/pcmcia/serial_cb.c
@@ -92,6 +92,7 @@ static dev_node_t *serial_attach(dev_locator_t *loc)
if (loc->bus != LOC_PCI) goto err_out;
pdev = pci_find_slot (loc->b.pci.bus, loc->b.pci.devfn);
if (!pdev) goto err_out;
+ if (pci_enable_device(pdev)) goto err_out;
printk(KERN_INFO "serial_attach(bus %d, fn %d)\n", pdev->bus->number, pdev->devfn);
io = pci_resource_start (pdev, 0);
diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c
index 2e2d391fa..b85a168de 100644
--- a/drivers/char/pcwd.c
+++ b/drivers/char/pcwd.c
@@ -414,7 +414,6 @@ static int pcwd_open(struct inode *ino, struct file *filep)
is_open = 1;
return(0);
case TEMP_MINOR:
- MOD_INC_USE_COUNT;
return(0);
default:
return (-ENODEV);
@@ -450,7 +449,6 @@ static ssize_t pcwd_read(struct file *file, char *buf, size_t count,
static int pcwd_close(struct inode *ino, struct file *filep)
{
- MOD_DEC_USE_COUNT;
if (MINOR(ino->i_rdev)==WATCHDOG_MINOR)
{
is_open = 0;
@@ -543,6 +541,7 @@ static void debug_off(void)
}
static struct file_operations pcwd_fops = {
+ owner: THIS_MODULE,
read: pcwd_read,
write: pcwd_write,
ioctl: pcwd_ioctl,
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index f4c84ac95..819ed0b1a 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -83,6 +83,63 @@ struct pp_struct {
/* ROUND_UP macro from fs/select.c */
#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
+struct pp_port_list_struct {
+ struct parport *port;
+ struct pp_port_list_struct *next;
+};
+static struct pp_port_list_struct *pp_port_list;
+static DECLARE_MUTEX(pp_port_list_lock);
+
+/* pp_attach and pp_detach are for keeping a list of currently
+ * available ports, held under a mutex. We do this rather than
+ * using parport_enumerate because it stops a load of races.
+ */
+
+static void pp_attach (struct parport *port)
+{
+ struct pp_port_list_struct *add;
+
+ add = kmalloc (sizeof (struct pp_port_list_struct), GFP_KERNEL);
+ if (!add) {
+ printk (KERN_WARNING CHRDEV ": memory squeeze\n");
+ return;
+ }
+
+ add->next = pp_port_list;
+ down (&pp_port_list_lock);
+ pp_port_list = add;
+ up (&pp_port_list_lock);
+}
+
+static void pp_detach (struct parport *port)
+{
+ struct pp_port_list_struct *del;
+
+ down (&pp_port_list_lock);
+ del = pp_port_list;
+ if (del->port == port)
+ pp_port_list = del->next;
+ else {
+ struct pp_port_list_struct *prev;
+ do {
+ prev = del;
+ del = del->next;
+ } while (del && del->port != port);
+ if (del)
+ prev->next = del->next;
+ }
+ up (&pp_port_list_lock);
+
+ if (del)
+ kfree (del);
+}
+
+static struct parport_driver ppdev_driver = {
+ name: CHRDEV,
+ attach: pp_attach,
+ detach: pp_detach
+};
+
static inline void pp_enable_irq (struct pp_struct *pp)
{
struct parport *port = pp->pdev->port;
@@ -216,7 +273,7 @@ static void pp_irq (int irq, void * private, struct pt_regs * unused)
static int register_device (int minor, struct pp_struct *pp)
{
- struct parport * port;
+ struct pp_port_list_struct *ports;
struct pardevice * pdev = NULL;
char *name;
int fl;
@@ -226,20 +283,24 @@ static int register_device (int minor, struct pp_struct *pp)
return -ENOMEM;
sprintf (name, CHRDEV "%x", minor);
- port = parport_enumerate (); /* FIXME: use attach/detach */
- while (port && port->number != minor)
- port = port->next;
+ down (&pp_port_list_lock);
+ ports = pp_port_list;
+ while (ports && ports->port->number != minor)
+ ports = ports->next;
+ if (ports->port) {
+ fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
+ pdev = parport_register_device (ports->port, name, NULL,
+ NULL, pp_irq, fl, pp);
+ }
+ up (&pp_port_list_lock);
- if (!port) {
+ if (!ports->port) {
printk (KERN_WARNING "%s: no associated port!\n", name);
kfree (name);
return -ENXIO;
}
- fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
- pdev = parport_register_device (port, name, NULL, NULL, pp_irq, fl,
- pp);
if (!pdev) {
printk (KERN_WARNING "%s: failed to register device!\n", name);
@@ -507,13 +568,9 @@ static int pp_open (struct inode * inode, struct file * file)
if (minor >= PARPORT_MAX)
return -ENXIO;
- MOD_INC_USE_COUNT;
-
pp = kmalloc (sizeof (struct pp_struct), GFP_KERNEL);
- if (!pp) {
- MOD_DEC_USE_COUNT;
+ if (!pp)
return -ENOMEM;
- }
pp->state.mode = IEEE1284_MODE_COMPAT;
pp->state.phase = init_phase (pp->state.mode);
@@ -565,7 +622,6 @@ static int pp_release (struct inode * inode, struct file * file)
kfree (pp);
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -583,6 +639,7 @@ static unsigned int pp_poll (struct file * file, poll_table * wait)
}
static struct file_operations pp_fops = {
+ owner: THIS_MODULE,
llseek: pp_lseek,
read: pp_read,
write: pp_write,
@@ -596,6 +653,10 @@ static devfs_handle_t devfs_handle = NULL;
static int __init ppdev_init (void)
{
+ if (parport_register_driver (&ppdev_driver)) {
+ printk (KERN_WARNING CHRDEV ": unable to register driver\n");
+ return -EIO;
+ }
if (devfs_register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
PP_MAJOR);
@@ -616,6 +677,7 @@ static void __exit ppdev_cleanup (void)
/* Clean up all parport stuff */
devfs_unregister (devfs_handle);
devfs_unregister_chrdev (PP_MAJOR, CHRDEV);
+ parport_unregister_driver (&ppdev_driver);
}
module_init(ppdev_init);
diff --git a/drivers/char/qpmouse.c b/drivers/char/qpmouse.c
index 096cf6afb..6fd5a3d65 100644
--- a/drivers/char/qpmouse.c
+++ b/drivers/char/qpmouse.c
@@ -133,8 +133,7 @@ static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
head &= QP_BUF_SIZE-1;
}
queue->head = head;
- if (queue->fasync)
- kill_fasync(queue->fasync, SIGIO, POLL_IN);
+ kill_fasync(&queue->fasync, SIGIO, POLL_IN);
wake_up_interruptible(&queue->proc_list);
}
@@ -151,7 +150,6 @@ static int release_qp(struct inode * inode, struct file * file)
if (!poll_qp_status())
printk("Warning: Mouse device busy in release_qp()\n");
free_irq(QP_IRQ, NULL);
- MOD_DEC_USE_COUNT;
}
return 0;
}
@@ -196,7 +194,6 @@ static int open_qp(struct inode * inode, struct file * file)
}
outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */
- MOD_INC_USE_COUNT;
return 0;
}
@@ -290,6 +287,7 @@ repeat:
}
struct file_operations qp_fops = {
+ owner: THIS_MODULE,
read: read_qp,
write: write_qp,
poll: poll_qp,
diff --git a/drivers/char/radio-aimslab.c b/drivers/char/radio-aimslab.c
index ee986b335..d716c54bd 100644
--- a/drivers/char/radio-aimslab.c
+++ b/drivers/char/radio-aimslab.c
@@ -355,7 +355,7 @@ static int __init rtrack_init(void)
return -EINVAL;
request_region(io, 2, "rtrack");
- printk(KERN_INFO "AIMSlab Radiotrack/radioreveal card driver.\n");
+ printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n");
/* Set up the I/O locking */
diff --git a/drivers/char/random.c b/drivers/char/random.c
index b983ae825..9f0e1374c 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -139,7 +139,7 @@
* add_interrupt_randomness() uses the inter-interrupt timing as random
* inputs to the entropy pool. Note that not all interrupts are good
* sources of randomness! For example, the timer interrupts is not a
- * good choice, because the periodicity of the interrupts is to
+ * good choice, because the periodicity of the interrupts is too
* regular, and hence predictable to an attacker. Disk interrupts are
* a better measure, since the timing of the disk interrupts are more
* unpredictable.
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 625f7022b..01865a09d 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -201,8 +201,6 @@ static void rio_close (void *ptr);
static int rio_chars_in_buffer (void * ptr);
static int rio_fw_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-static int rio_fw_open(struct inode *inode, struct file *filp);
-static INT rio_fw_release(struct inode *inode, struct file *filp);
static int rio_init_drivers(void);
@@ -277,9 +275,8 @@ static struct real_driver rio_real_driver = {
*/
static struct file_operations rio_fw_fops = {
+ owner: THIS_MODULE,
ioctl: rio_fw_ioctl,
- open: rio_fw_open,
- release: rio_fw_release,
};
struct miscdevice rio_fw_device = {
@@ -634,32 +631,6 @@ static void rio_shutdown_port (void * ptr)
func_exit();
}
-
-
-/* ********************************************************************** *
- * Here are the routines that actually *
- * interface with the rest of the system *
- * ********************************************************************** */
-
-
-static int rio_fw_open(struct inode *inode, struct file *filp)
-{
- func_enter ();
- rio_inc_mod_count ();
- func_exit ();
- return 0;
-}
-
-
-static INT rio_fw_release(struct inode *inode, struct file *filp)
-{
- func_enter ();
- rio_dec_mod_count ();
- func_exit ();
- return NO_ERROR;
-}
-
-
/* I haven't the foggiest why the decrement use count has to happen
here. The whole linux serial drivers stuff needs to be redesigned.
My guess is that this is a hack to minimize the impact of a bug
@@ -1149,6 +1120,7 @@ int rio_init(void)
while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
pdev))) {
+ if (pci_enable_device(pdev)) continue;
#else
for (i=0;i< RIO_NBOARDS;i++) {
if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX,
@@ -1234,6 +1206,7 @@ int rio_init(void)
while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
PCI_DEVICE_ID_SPECIALIX_RIO,
pdev))) {
+ if (pci_enable_device(pdev)) continue;
#else
for (i=0;i< RIO_NBOARDS;i++) {
if (pcibios_find_device (PCI_VENDOR_ID_SPECIALIX,
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 29d4227ff..943ea6a61 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -1957,7 +1957,10 @@ int __init register_PCI(int i, unsigned int bus, unsigned int device_fn)
if (!dev)
return 0;
- rcktpt_io_addr[i] = dev->resource[0].start;
+ if (pci_enable_device(dev))
+ return 0;
+
+ rcktpt_io_addr[i] = pci_resource_start (dev, 0);
switch(dev->device) {
case PCI_DEVICE_ID_RP4QUAD:
str = "Quadcable";
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index bfe700219..9809952ea 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -179,8 +179,7 @@ static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* Now do the rest of the actions */
wake_up_interruptible(&rtc_wait);
- if (rtc_async_queue)
- kill_fasync (rtc_async_queue, SIGIO, POLL_IN);
+ kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
}
#endif
@@ -513,8 +512,6 @@ static int rtc_open(struct inode *inode, struct file *file)
if(rtc_status & RTC_IS_OPEN)
return -EBUSY;
- MOD_INC_USE_COUNT;
-
rtc_status |= RTC_IS_OPEN;
spin_lock_irq (&rtc_lock);
@@ -558,7 +555,6 @@ static int rtc_release(struct inode *inode, struct file *file)
}
#endif
- MOD_DEC_USE_COUNT;
spin_lock_irq (&rtc_lock);
rtc_irq_data = 0;
@@ -590,6 +586,7 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait)
*/
static struct file_operations rtc_fops = {
+ owner: THIS_MODULE,
llseek: rtc_llseek,
read: rtc_read,
#if !defined(__alpha__) && !defined(CONFIG_DECSTATION)
@@ -783,8 +780,7 @@ static void rtc_dropped_irq(unsigned long data)
/* Now we have new data */
wake_up_interruptible(&rtc_wait);
- if (rtc_async_queue)
- kill_fasync (rtc_async_queue, SIGIO, POLL_IN);
+ kill_fasync (&rtc_async_queue, SIGIO, POLL_IN);
}
#endif
diff --git a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c
new file mode 100644
index 000000000..a0bea62c0
--- /dev/null
+++ b/drivers/char/sbc60xxwdt.c
@@ -0,0 +1,338 @@
+/*
+ * 60xx Single Board Computer Watchdog Timer driver for Linux 2.2.x
+ *
+ * Based on acquirewdt.c by Alan Cox.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * The author does NOT admit liability nor provide warranty for
+ * any of this software. This material is provided "AS-IS" in
+ * the hope that it may be useful for others.
+ *
+ * (c) Copyright 2000 Jakob Oestergaard <jakob@ostenfeld.dk>
+ *
+ * 12/4 - 2000 [Initial revision]
+ * 25/4 - 2000 Added /dev/watchdog support
+ *
+ *
+ * Theory of operation:
+ * A Watchdog Timer (WDT) is a hardware circuit that can
+ * reset the computer system in case of a software fault.
+ * You probably knew that already.
+ *
+ * Usually a userspace daemon will notify the kernel WDT driver
+ * via the /proc/watchdog special device file that userspace is
+ * still alive, at regular intervals. When such a notification
+ * occurs, the driver will usually tell the hardware watchdog
+ * that everything is in order, and that the watchdog should wait
+ * for yet another little while to reset the system.
+ * If userspace fails (RAM error, kernel bug, whatever), the
+ * notifications cease to occur, and the hardware watchdog will
+ * reset the system (causing a reboot) after the timeout occurs.
+ *
+ * This WDT driver is different from the other Linux WDT
+ * drivers in several ways:
+ * *) The driver will ping the watchdog by itself, because this
+ * particular WDT has a very short timeout (one second) and it
+ * would be insane to count on any userspace daemon always
+ * getting scheduled within that time frame.
+ * *) This driver expects the userspace daemon to send a specific
+ * character code ('V') to /dev/watchdog before closing the
+ * /dev/watchdog file. If the userspace daemon closes the file
+ * without sending this special character, the driver will assume
+ * that the daemon (and userspace in general) died, and will
+ * stop pinging the WDT without disabling it first. This will
+ * cause a reboot.
+ *
+ * Why `V' ? Well, `V' is the character in ASCII for the value 86,
+ * and we all know that 86 is _the_ most random number in the universe.
+ * Therefore it is the letter that has the slightest chance of occuring
+ * by chance, when the system becomes corrupted.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#define OUR_NAME "sbc60xxwdt"
+
+/*
+ * You must set these - The driver cannot probe for the settings
+ */
+
+#define WDT_STOP 0x45
+#define WDT_START 0x443
+
+/*
+ * The 60xx board can use watchdog timeout values from one second
+ * to several minutes. The default is one second, so if we reset
+ * the watchdog every ~250ms we should be safe.
+ */
+
+#define WDT_INTERVAL (HZ/4+1)
+
+/*
+ * We must not require too good response from the userspace daemon.
+ * Here we require the userspace daemon to send us a heartbeat
+ * char to /dev/watchdog every 10 seconds.
+ * If the daemon pulses us every 5 seconds, we can still afford
+ * a 5 second scheduling delay on the (high priority) daemon. That
+ * should be sufficient for a box under any load.
+ */
+
+#define WDT_HEARTBEAT (HZ * 10)
+
+static void wdt_timer_ping(unsigned long);
+static struct timer_list timer;
+static unsigned long next_heartbeat = 0;
+static int wdt_is_open = 0;
+static int wdt_expect_close = 0;
+
+/*
+ * Whack the dog
+ */
+
+static void wdt_timer_ping(unsigned long data)
+{
+ /* If we got a heartbeat pulse within the WDT_US_INTERVAL
+ * we agree to ping the WDT
+ */
+ if(time_before(jiffies, next_heartbeat))
+ {
+ /* Ping the WDT by reading from WDT_START */
+ inb_p(WDT_START);
+ /* Re-set the timer interval */
+ timer.expires = jiffies + WDT_INTERVAL;
+ add_timer(&timer);
+ } else {
+ printk(OUR_NAME ": Heartbeat lost! Will not ping the watchdog\n");
+ }
+}
+
+/*
+ * Utility routines
+ */
+
+static void wdt_startup(void)
+{
+ next_heartbeat = jiffies + WDT_HEARTBEAT;
+
+ /* Start the timer */
+ timer.expires = jiffies + WDT_INTERVAL;
+ add_timer(&timer);
+ printk(OUR_NAME ": Watchdog timer is now enabled.\n");
+}
+
+static void wdt_turnoff(void)
+{
+ /* Stop the timer */
+ del_timer(&timer);
+ inb_p(WDT_STOP);
+ printk(OUR_NAME ": Watchdog timer is now disabled...\n");
+}
+
+
+/*
+ * /dev/watchdog handling
+ */
+
+static ssize_t fop_write(struct file * file, const char * buf, size_t count, loff_t * ppos)
+{
+ /* We can't seek */
+ if(ppos != &file->f_pos)
+ return -ESPIPE;
+
+ /* See if we got the magic character */
+ if(count)
+ {
+ size_t ofs;
+
+ /* note: just in case someone wrote the magic character
+ * five months ago... */
+ wdt_expect_close = 0;
+
+ /* now scan */
+ for(ofs = 0; ofs != count; ofs++)
+ if(buf[ofs] == 'V')
+ wdt_expect_close = 1;
+
+ /* Well, anyhow someone wrote to us, we should return that favour */
+ next_heartbeat = jiffies + WDT_HEARTBEAT;
+ }
+ return 0;
+}
+
+static ssize_t fop_read(struct file * file, char * buf, size_t count, loff_t * ppos)
+{
+ /* No can do */
+ return -EINVAL;
+}
+
+static int fop_open(struct inode * inode, struct file * file)
+{
+ switch(MINOR(inode->i_rdev))
+ {
+ case WATCHDOG_MINOR:
+ /* Just in case we're already talking to someone... */
+ if(wdt_is_open)
+ return -EBUSY;
+ /* Good, fire up the show */
+ wdt_is_open = 1;
+ wdt_startup();
+ return 0;
+
+ default:
+ return -ENODEV;
+ }
+}
+
+static int fop_close(struct inode * inode, struct file * file)
+{
+ if(MINOR(inode->i_rdev) == WATCHDOG_MINOR)
+ {
+ if(wdt_expect_close)
+ wdt_turnoff();
+ else {
+ del_timer(&timer);
+ printk(OUR_NAME ": device file closed unexpectedly. Will not stop the WDT!\n");
+ }
+ }
+ wdt_is_open = 0;
+ return 0;
+}
+
+static long long fop_llseek(struct file *file, long long offset, int origin)
+{
+ return -ESPIPE;
+}
+
+static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ static struct watchdog_info ident=
+ {
+ 0,
+ 1,
+ "SB60xx"
+ };
+
+ switch(cmd)
+ {
+ default:
+ return -ENOIOCTLCMD;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident))?-EFAULT:0;
+ case WDIOC_KEEPALIVE:
+ next_heartbeat = jiffies + WDT_HEARTBEAT;
+ return 0;
+ }
+}
+
+static struct file_operations wdt_fops = {
+ owner: THIS_MODULE,
+ llseek: fop_llseek,
+ read: fop_read,
+ write: fop_write,
+ open: fop_open,
+ release: fop_close,
+ ioctl: fop_ioctl
+};
+
+static struct miscdevice wdt_miscdev = {
+ WATCHDOG_MINOR,
+ "watchdog",
+ &wdt_fops
+};
+
+/*
+ * Notifier for system down
+ */
+
+static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ if(code==SYS_DOWN || code==SYS_HALT)
+ wdt_turnoff();
+ return NOTIFY_DONE;
+}
+
+/*
+ * The WDT needs to learn about soft shutdowns in order to
+ * turn the timebomb registers off.
+ */
+
+static struct notifier_block wdt_notifier=
+{
+ wdt_notify_sys,
+ 0,
+ 0
+};
+
+static void __exit sbc60xxwdt_unload(void)
+{
+ wdt_turnoff();
+
+ /* Deregister */
+ misc_deregister(&wdt_miscdev);
+
+ unregister_reboot_notifier(&wdt_notifier);
+ release_region(WDT_START,1);
+ release_region(WDT_STOP,1);
+}
+
+static int __init sbc60xxwdt_init(void)
+{
+ int rc = -EBUSY;
+
+ if (!request_region(WDT_STOP, 1, "SBC 60XX WDT"))
+ goto err_out;
+ if (!request_region(WDT_START, 1, "SBC 60XX WDT"))
+ goto err_out_region1;
+
+ init_timer(&timer);
+ timer.function = wdt_timer_ping;
+ timer.data = 0;
+
+ rc = misc_register(&wdt_miscdev);
+ if (rc)
+ goto err_out_region2;
+
+ rc = register_reboot_notifier(&wdt_notifier);
+ if (rc)
+ goto err_out_miscdev;
+
+ printk(KERN_INFO OUR_NAME ": WDT driver for 60XX single board computer initialised.\n");
+
+ return 0;
+
+err_out_miscdev:
+ misc_deregister(&wdt_miscdev);
+err_out_region2:
+ release_region(WDT_START,1);
+err_out_region1:
+ release_region(WDT_STOP,1);
+err_out:
+ return rc;
+}
+
+module_init(sbc60xxwdt_init);
+module_exit(sbc60xxwdt_unload)
diff --git a/drivers/char/scan_keyb.c b/drivers/char/scan_keyb.c
new file mode 100644
index 000000000..7536c0769
--- /dev/null
+++ b/drivers/char/scan_keyb.c
@@ -0,0 +1,129 @@
+/*
+ * $Id: scan_keyb.c,v 1.1 2000/06/10 21:45:30 yaegashi Exp $
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ * Generic scan keyboard driver
+ */
+
+#include <linux/config.h>
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/mm.h>
+#include <linux/signal.h>
+#include <linux/init.h>
+#include <linux/kbd_ll.h>
+#include <linux/delay.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/miscdevice.h>
+#include <linux/malloc.h>
+#include <linux/kbd_kern.h>
+
+struct scan_keyboard {
+ struct scan_keyboard *next;
+ void (*scan)(unsigned char *buffer);
+ const unsigned char *table;
+ unsigned char *s0, *s1;
+ int length;
+};
+
+static struct scan_keyboard *keyboards=NULL;
+static struct tq_struct task_scan_kbd;
+
+static void check_kbd(const unsigned char *table,
+ unsigned char *new, unsigned char *old, int length)
+{
+ int need_tasklet_schedule=0;
+ unsigned char xor, bit;
+
+ while(length-->0) {
+ if((xor=*new^*old)==0) {
+ table+=8;
+ }
+ else {
+ for(bit=0x80; bit!=0; bit>>=1) {
+ if(xor&bit) {
+ handle_scancode(*table, !(*new&bit));
+ need_tasklet_schedule=1;
+ }
+ table++;
+ }
+ }
+ new++; old++;
+ }
+
+ if(need_tasklet_schedule)
+ tasklet_schedule(&keyboard_tasklet);
+}
+
+
+static void scan_kbd(void *dummy)
+{
+ struct scan_keyboard *kbd;
+
+ for(kbd=keyboards; kbd!=NULL; kbd=kbd->next) {
+ if(jiffies&1) {
+ kbd->scan(kbd->s0);
+ check_kbd(kbd->table, kbd->s0, kbd->s1, kbd->length);
+ }
+ else {
+ kbd->scan(kbd->s1);
+ check_kbd(kbd->table, kbd->s1, kbd->s0, kbd->length);
+ }
+
+ }
+ queue_task(&task_scan_kbd, &tq_timer);
+}
+
+
+int register_scan_keyboard(void (*scan)(unsigned char *buffer),
+ const unsigned char *table,
+ int length)
+{
+ struct scan_keyboard *kbd;
+
+ if((kbd=kmalloc(sizeof(struct scan_keyboard), GFP_KERNEL))==NULL)
+ goto error_out;
+
+ kbd->scan=scan;
+ kbd->table=table;
+ kbd->length=length;
+
+ kbd->s0=kbd->s1=NULL;
+ if((kbd->s0=kmalloc(length, GFP_KERNEL))==NULL)
+ goto error_out;
+ if((kbd->s1=kmalloc(length, GFP_KERNEL))==NULL)
+ goto error_out;
+
+ kbd->scan(kbd->s0);
+ kbd->scan(kbd->s1);
+
+ kbd->next=keyboards;
+ keyboards=kbd;
+
+ return 0;
+
+ error_mem_free:
+ if(kbd->s0)
+ kfree(kbd->s0);
+ if(kbd->s1)
+ kfree(kbd->s1);
+ kfree(kbd);
+
+ error_out:
+ return -ENOMEM;
+}
+
+
+void __init scan_kbd_init(void)
+{
+
+ task_scan_kbd.next=NULL;
+ task_scan_kbd.sync=0;
+ task_scan_kbd.routine=scan_kbd;
+ task_scan_kbd.data=NULL;
+ queue_task(&task_scan_kbd, &tq_timer);
+ printk(KERN_INFO "Generic scan keyboard driver initialized\n");
+}
diff --git a/drivers/char/scan_keyb.h b/drivers/char/scan_keyb.h
new file mode 100644
index 000000000..849b50870
--- /dev/null
+++ b/drivers/char/scan_keyb.h
@@ -0,0 +1,15 @@
+#ifndef __DRIVER_CHAR_SCAN_KEYB_H
+#define __DRIVER_CHAR_SCAN_KEYB_H
+/*
+ * $Id: scan_keyb.h,v 1.1 2000/06/10 21:45:30 yaegashi Exp $
+ * Copyright (C) 2000 YAEGASHI Takeshi
+ * Generic scan keyboard driver
+ */
+
+int register_scan_keyboard(void (*scan)(unsigned char *buffer),
+ const unsigned char *table,
+ int length);
+
+void __init scan_kbd_init(void);
+
+#endif
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 458cbad6e..82d1bf131 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -43,13 +43,16 @@
* few races on freeing buffers too.
* Alan Modra <alan@linuxcare.com>
*
+ * 5/00: Support for the RSA-DV II/S card added.
+ * Kiyokazu SUTO <suto@ks-and-ks.ne.jp>
+ *
* This module exports the following rs232 io functions:
*
* int rs_init(void);
*/
-static char *serial_version = "4.93";
-static char *serial_revdate = "2000-03-20";
+static char *serial_version = "5.01";
+static char *serial_revdate = "2000-05-29";
/*
* Serial driver configuration section. Here are the various options:
@@ -134,6 +137,8 @@ static char *serial_revdate = "2000-03-20";
#endif
#endif
+#define CONFIG_SERIAL_RSA
+
#define RS_STROBE_TIME (10*HZ)
#define RS_ISR_PASS_LIMIT 256
@@ -277,9 +282,20 @@ static struct serial_uart_config uart_config[] = {
UART_STARTECH },
{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
UART_STARTECH },
+ { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO },
{ 0, 0}
};
+#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+
+#define PORT_RSA_MAX 4
+static int probe_rsa[PORT_RSA_MAX];
+static int force_rsa[PORT_RSA_MAX];
+
+MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i");
+#endif /* CONFIG_SERIAL_RSA */
+
static struct serial_state rs_table[RS_TABLE_SIZE] = {
SERIAL_PORT_DFNS /* Defined in serial.h */
};
@@ -293,11 +309,8 @@ static struct serial_state rs_table[RS_TABLE_SIZE] = {
static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS];
static int serial_pci_board_idx = 0;
#endif
-#ifndef PCI_BASE_ADDRESS
-#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start)
-#define PCI_BASE_REGION_SIZE(dev, r) ((dev)->resource[r].end - \
- (dev)->resource[r].start)
-#define IS_PCI_REGION_IOPORT(dev, r) ((dev)->resource[r].flags & \
+#ifndef IS_PCI_REGION_IOPORT
+#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
IORESOURCE_IO)
#endif
#ifndef PCI_IRQ_RESOURCE
@@ -314,7 +327,8 @@ static int serial_pci_board_idx = 0;
#define ACTIVATE_FUNC(dev) (dev->activate)
#define DEACTIVATE_FUNC(dev) (dev->deactivate)
#endif
-
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
static struct tty_struct *serial_table[NR_PORTS];
static struct termios *serial_termios[NR_PORTS];
@@ -996,6 +1010,9 @@ static void do_softint(void *private_)
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+ wake_up_interruptible(&tty->poll_wait);
+#endif
}
}
@@ -1090,6 +1107,50 @@ static void figure_IRQ_timeout(int irq)
IRQ_timeout[irq] = timeout ? timeout : 1;
}
+#ifdef CONFIG_SERIAL_RSA
+/* Attempts to turn on the RSA FIFO. Returns zero on failure */
+static int enable_rsa(struct async_struct *info)
+{
+ unsigned char mode;
+ int result;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ mode = serial_inp(info, UART_RSA_MSR);
+ result = mode & UART_RSA_MSR_FIFO;
+
+ if (!result) {
+ serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO);
+ mode = serial_inp(info, UART_RSA_MSR);
+ result = mode & UART_RSA_MSR_FIFO;
+ }
+
+ restore_flags(flags);
+ return result;
+}
+
+/* Attempts to turn off the RSA FIFO. Returns zero on failure */
+static int disable_rsa(struct async_struct *info)
+{
+ unsigned char mode;
+ int result;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ mode = serial_inp(info, UART_RSA_MSR);
+ result = !(mode & UART_RSA_MSR_FIFO);
+
+ if (!result) {
+ serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO);
+ mode = serial_inp(info, UART_RSA_MSR);
+ result = !(mode & UART_RSA_MSR_FIFO);
+ }
+
+ restore_flags(flags);
+ return result;
+}
+#endif /* CONFIG_SERIAL_RSA */
+
static int startup(struct async_struct * info)
{
unsigned long flags;
@@ -1127,7 +1188,7 @@ static int startup(struct async_struct * info)
printk("starting up ttys%d (irq %d)...", info->line, state->irq);
#endif
- if (uart_config[info->state->type].flags & UART_STARTECH) {
+ if (uart_config[state->type].flags & UART_STARTECH) {
/* Wake up UART */
serial_outp(info, UART_LCR, 0xBF);
serial_outp(info, UART_EFR, UART_EFR_ECB);
@@ -1145,7 +1206,7 @@ static int startup(struct async_struct * info)
/*
* For a XR16C850, we need to set the trigger levels
*/
- if (info->state->type == PORT_16850) {
+ if (state->type == PORT_16850) {
serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
UART_FCTR_RX);
serial_outp(info, UART_TRG, UART_TRG_96);
@@ -1156,12 +1217,12 @@ static int startup(struct async_struct * info)
serial_outp(info, UART_LCR, 0);
}
- if (info->state->type == PORT_16750) {
+ if (state->type == PORT_16750) {
/* Wake up UART */
serial_outp(info, UART_IER, 0);
}
- if (info->state->type == PORT_16C950) {
+ if (state->type == PORT_16C950) {
/* Wake up and initialize UART */
info->ACR = 0;
serial_outp(info, UART_LCR, 0xBF);
@@ -1174,6 +1235,20 @@ static int startup(struct async_struct * info)
serial_outp(info, UART_LCR, 0);
}
+#ifdef CONFIG_SERIAL_RSA
+ /*
+ * If this is an RSA port, see if we can kick it up to the
+ * higher speed clock.
+ */
+ if (state->type == PORT_RSA) {
+ if (state->baud_base != SERIAL_RSA_BAUD_BASE &&
+ enable_rsa(info))
+ state->baud_base = SERIAL_RSA_BAUD_BASE;
+ if (state->baud_base == SERIAL_RSA_BAUD_BASE)
+ serial_outp(info, UART_RSA_FRR, 0);
+ }
+#endif
+
/*
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
@@ -1199,7 +1274,8 @@ static int startup(struct async_struct * info)
* if it is, then bail out, because there's likely no UART
* here.
*/
- if (serial_inp(info, UART_LSR) == 0xff) {
+ if (!(info->flags & ASYNC_BUGGY_UART) &&
+ (serial_inp(info, UART_LSR) == 0xff)) {
printk("LSR safety check engaged!\n");
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
@@ -1425,6 +1501,17 @@ static void shutdown(struct async_struct * info)
UART_FCR_CLEAR_XMIT));
serial_outp(info, UART_FCR, 0);
+#ifdef CONFIG_SERIAL_RSA
+ /*
+ * Reset the RSA board back to 115kbps compat mode.
+ */
+ if ((state->type == PORT_RSA) &&
+ (state->baud_base == SERIAL_RSA_BAUD_BASE &&
+ disable_rsa(info)))
+ state->baud_base = SERIAL_RSA_BAUD_BASE_LO;
+#endif
+
+
(void)serial_in(info, UART_RX); /* read data port to reset things */
if (info->tty)
@@ -1522,6 +1609,12 @@ static void change_speed(struct async_struct *info,
baud = tty_get_baud_rate(info->tty);
if (!baud)
baud = 9600; /* B0 transition handled in rs_set_termios */
+#ifdef CONFIG_SERIAL_RSA
+ if ((info->state->type == PORT_RSA) &&
+ (info->state->baud_base != SERIAL_RSA_BAUD_BASE) &&
+ enable_rsa(info))
+ info->state->baud_base = SERIAL_RSA_BAUD_BASE;
+#endif
baud_base = info->state->baud_base;
if (info->state->type == PORT_16C950) {
if (baud <= baud_base)
@@ -1583,6 +1676,10 @@ static void change_speed(struct async_struct *info,
if (uart_config[info->state->type].flags & UART_USE_FIFO) {
if ((info->state->baud_base / quot) < 2400)
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
+#ifdef CONFIG_SERIAL_RSA
+ else if (info->state->type == PORT_RSA)
+ fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
+#endif
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
}
@@ -1810,6 +1907,9 @@ static void rs_flush_buffer(struct tty_struct *tty)
info->xmit.head = info->xmit.tail = 0;
restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
+#ifdef SERIAL_HAVE_POLL_WAIT
+ wake_up_interruptible(&tty->poll_wait);
+#endif
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup)(tty);
@@ -1912,6 +2012,10 @@ static int get_serial_info(struct async_struct * info,
tmp.type = state->type;
tmp.line = state->line;
tmp.port = state->port;
+ if (HIGH_BITS_OFFSET)
+ tmp.port_high = state->port >> HIGH_BITS_OFFSET;
+ else
+ tmp.port_high = 0;
tmp.irq = state->irq;
tmp.flags = state->flags;
tmp.xmit_fifo_size = state->xmit_fifo_size;
@@ -1933,14 +2037,19 @@ static int set_serial_info(struct async_struct * info,
struct serial_state old_state, *state;
unsigned int i,change_irq,change_port;
int retval = 0;
+ unsigned long new_port;
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
state = info->state;
old_state = *state;
-
+
+ new_port = new_serial.port;
+ if (HIGH_BITS_OFFSET)
+ new_port += new_serial.port_high << HIGH_BITS_OFFSET;
+
change_irq = new_serial.irq != state->irq;
- change_port = (new_serial.port != state->port) ||
+ change_port = (new_port != ((int) state->port)) ||
(new_serial.hub6 != state->hub6);
if (!capable(CAP_SYS_ADMIN)) {
@@ -1978,7 +2087,7 @@ static int set_serial_info(struct async_struct * info,
if (new_serial.type) {
for (i = 0 ; i < NR_PORTS; i++)
if ((state != &rs_table[i]) &&
- (rs_table[i].port == new_serial.port) &&
+ (rs_table[i].port == new_port) &&
rs_table[i].type)
return -EADDRINUSE;
}
@@ -2005,8 +2114,14 @@ static int set_serial_info(struct async_struct * info,
info->xmit_fifo_size = state->xmit_fifo_size =
new_serial.xmit_fifo_size;
- if ((state->type != PORT_UNKNOWN) && state->port)
+ if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+ if (old_state.type == PORT_RSA)
+ release_region(state->port + UART_RSA_BASE, 16);
+ else
+#endif
release_region(state->port,8);
+ }
state->type = new_serial.type;
if (change_port || change_irq) {
/*
@@ -2015,15 +2130,22 @@ static int set_serial_info(struct async_struct * info,
*/
shutdown(info);
state->irq = new_serial.irq;
- info->port = state->port = new_serial.port;
+ info->port = state->port = new_port;
info->hub6 = state->hub6 = new_serial.hub6;
if (info->hub6)
info->io_type = state->io_type = SERIAL_IO_HUB6;
else if (info->io_type == SERIAL_IO_HUB6)
info->io_type = state->io_type = SERIAL_IO_PORT;
}
- if ((state->type != PORT_UNKNOWN) && state->port)
- request_region(state->port,8,"serial(set)");
+ if ((state->type != PORT_UNKNOWN) && state->port) {
+#ifdef CONFIG_SERIAL_RSA
+ if (state->type == PORT_RSA)
+ request_region(state->port + UART_RSA_BASE,
+ 16, "serial_rsa(set)");
+ else
+#endif
+ request_region(state->port,8,"serial(set)");
+ }
check_and_exit:
@@ -2462,6 +2584,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
/* note the counters on entry */
cprev = info->state->icount;
restore_flags(flags);
+ /* Force modem status interrupts on */
+ info->IER |= UART_IER_MSI;
+ serial_out(info, UART_IER, info->IER);
while (1) {
interruptible_sleep_on(&info->delta_msr_wait);
/* see if a signal did it */
@@ -3348,6 +3473,16 @@ static void autoconfig_startech_uarts(struct async_struct *info,
* LSR register (which serial_icr_read does)
*/
if (state->type == PORT_16550A) {
+ /*
+ * EFR [4] must be set else this test fails
+ *
+ * This shouldn't be necessary, but Mike Hudson
+ * (Exoray@isys.ca) claims that it's needed for 952
+ * dual UART's (which are not recommended for new designs).
+ */
+ serial_out(info, UART_LCR, 0xBF);
+ serial_out(info, UART_EFR, 0x10);
+ serial_out(info, UART_LCR, 0x00);
/* Check for Oxford Semiconductor 16C950 */
scratch = serial_icr_read(info, UART_ID1);
scratch2 = serial_icr_read(info, UART_ID2);
@@ -3434,7 +3569,8 @@ static void autoconfig(struct serial_state * state)
save_flags(flags); cli();
- if (!state->iomem_base) {
+ if (!(state->flags & ASYNC_BUGGY_UART) &&
+ !state->iomem_base) {
/*
* Do a simple existence test first; if we fail this,
* there's no point trying anything else.
@@ -3459,8 +3595,9 @@ static void autoconfig(struct serial_state * state)
serial_outp(info, UART_IER, scratch);
if (scratch2 || scratch3 != 0x0F) {
#ifdef SERIAL_DEBUG_AUTOCONF
- printk("serial: ttyS%d: simple autoconfig failed\n",
- state->line);
+ printk("serial: ttyS%d: simple autoconfig failed "
+ "(%02x, %02x)\n", state->line,
+ scratch2, scratch3);
#endif
restore_flags(flags);
return; /* We failed; there's nothing here */
@@ -3545,6 +3682,25 @@ static void autoconfig(struct serial_state * state)
}
serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
}
+#if defined(CONFIG_SERIAL_RSA) && defined(MODULE)
+ if (state->type == PORT_16550A) {
+ int i;
+
+ for (i = 0 ; i < PORT_RSA_MAX ; ++i) {
+ if (!probe_rsa[i] && !force_rsa[i])
+ break;
+ if (((probe_rsa[i] != state->port) ||
+ check_region(state->port + UART_RSA_BASE, 16)) &&
+ (force_rsa[i] != state->port))
+ continue;
+ if (!enable_rsa(info))
+ continue;
+ state->type = PORT_RSA;
+ state->baud_base = SERIAL_RSA_BAUD_BASE;
+ break;
+ }
+ }
+#endif
serial_outp(info, UART_LCR, save_lcr);
if (state->type == PORT_16450) {
scratch = serial_in(info, UART_SCR);
@@ -3564,12 +3720,23 @@ static void autoconfig(struct serial_state * state)
return;
}
- if (info->port)
- request_region(info->port,8,"serial(auto)");
+ if (info->port) {
+#ifdef CONFIG_SERIAL_RSA
+ if (state->type == PORT_RSA)
+ request_region(info->port + UART_RSA_BASE, 16,
+ "serial_rsa(auto)");
+ else
+#endif
+ request_region(info->port,8,"serial(auto)");
+ }
/*
* Reset the UART.
*/
+#ifdef CONFIG_SERIAL_RSA
+ if (state->type == PORT_RSA)
+ serial_outp(info, UART_RSA_FRR, 0);
+#endif
serial_outp(info, UART_MCR, save_mcr);
serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR |
@@ -3614,7 +3781,7 @@ static void __init printk_pnp_dev_id(unsigned short vendor,
static _INLINE_ int get_pci_port(struct pci_dev *dev,
struct pci_board *board,
- struct serial_struct *state,
+ struct serial_struct *req,
int idx)
{
unsigned long port;
@@ -3626,24 +3793,28 @@ static _INLINE_ int get_pci_port(struct pci_dev *dev,
base_idx += idx;
if (board->flags & SPCI_FL_REGION_SZ_CAP) {
- max_port = PCI_BASE_REGION_SIZE(dev, base_idx) / 8;
+ max_port = pci_resource_len(dev, base_idx) / 8;
if (idx >= max_port)
return 1;
}
- port = PCI_BASE_ADDRESS(dev, base_idx) + board->first_uart_offset;
+ port = pci_resource_start(dev, base_idx) + board->first_uart_offset;
if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
port += idx * (board->uart_offset ? board->uart_offset : 8);
if (IS_PCI_REGION_IOPORT(dev, base_idx)) {
- state->port = port;
+ req->port = port;
+ if (HIGH_BITS_OFFSET)
+ req->port_high = port >> HIGH_BITS_OFFSET;
+ else
+ req->port_high = 0;
return 0;
}
- state->io_type = SERIAL_IO_MEM;
- state->iomem_base = ioremap(port, board->uart_offset);
- state->iomem_reg_shift = board->reg_shift;
- state->port = 0;
+ req->io_type = SERIAL_IO_MEM;
+ req->iomem_base = ioremap(port, board->uart_offset);
+ req->iomem_reg_shift = board->reg_shift;
+ req->port = 0;
return 0;
}
@@ -3670,23 +3841,28 @@ static void __init start_pci_pnp_board(struct pci_dev *dev,
struct pci_board *board)
{
int k, line;
- struct serial_struct fake_state;
+ struct serial_struct serial_req;
int base_baud;
if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
- printk("SERIAL: PNP device '");
+ printk("serial: PNP device '");
printk_pnp_dev_id(board->vendor, board->device);
printk("' prepare failed\n");
return;
}
if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
- printk("SERIAL: PNP device '");
+ printk("serial: PNP device '");
printk_pnp_dev_id(board->vendor, board->device);
printk("' activate failed\n");
return;
}
+ if (!(board->flags & SPCI_FL_ISPNP) && pci_enable_device(dev)) {
+ printk("serial: PCI device enable failed\n");
+ return;
+ }
+
/*
* Run the initialization function, if any
*/
@@ -3710,18 +3886,18 @@ static void __init start_pci_pnp_board(struct pci_dev *dev,
base_baud = board->base_baud;
if (!base_baud)
base_baud = BASE_BAUD;
- memset(&fake_state, 0, sizeof(fake_state));
+ memset(&serial_req, 0, sizeof(serial_req));
for (k=0; k < board->num_ports; k++) {
- fake_state.irq = get_pci_irq(dev, board, k);
- if (get_pci_port(dev, board, &fake_state, k))
+ serial_req.irq = get_pci_irq(dev, board, k);
+ if (get_pci_port(dev, board, &serial_req, k))
break;
- fake_state.flags = ASYNC_SKIP_TEST;
+ serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE;
#ifdef SERIAL_DEBUG_PCI
printk("Setup PCI/PNP port: port %x, irq %d, type %d\n",
- fake_state.port, fake_state.irq, fake_state.io_type);
+ serial_req.port, serial_req.irq, serial_req.io_type);
#endif
- line = register_serial(&fake_state);
+ line = register_serial(&serial_req);
if (line < 0)
break;
rs_table[line].baud_base = base_baud;
@@ -3742,28 +3918,45 @@ __init
#endif
pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
{
- u8 data, *p, scratch;
+ u8 data, *p, irq_config;
+ int pci_config;
+ irq_config = 0x41;
+ pci_config = PCI_COMMAND_MEMORY;
+ if (dev->vendor == PCI_VENDOR_ID_PANACOM)
+ irq_config = 0x43;
+ if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
+ (dev->device == PCI_VENDOR_ID_PLX_ROMULUS)) {
+ /*
+ * As the megawolf cards have the int pins active
+ * high, and have 2 UART chips, both ints must be
+ * enabled on the 9050. Also, the UARTS are set in
+ * 16450 mode by default, so we have to enable the
+ * 16C950 'enhanced' mode so that we can use the deep
+ * FIFOs
+ */
+ irq_config = 0x5b;
+ pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+ }
+
pci_read_config_byte(dev, PCI_COMMAND, &data);
if (enable)
pci_write_config_byte(dev, PCI_COMMAND,
- data | PCI_COMMAND_MEMORY);
+ data | pci_config);
/* enable/disable interrupts */
- p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80);
- scratch = 0x41;
- if (dev->vendor == PCI_VENDOR_ID_PANACOM)
- scratch = 0x43;
- writel(enable ? scratch : 0x00, (unsigned long)p + 0x4c);
+ p = ioremap(pci_resource_start(dev, 0), 0x80);
+ writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c);
iounmap(p);
if (!enable)
pci_write_config_byte(dev, PCI_COMMAND,
- data & ~PCI_COMMAND_MEMORY);
+ data & ~pci_config);
return 0;
}
+
/*
* SIIG serial cards have an PCI interface chip which also controls
* the UART clocking frequency. Each UART can be clocked independently
@@ -3796,7 +3989,7 @@ pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
if (!enable) return 0;
- p = ioremap(PCI_BASE_ADDRESS(dev, 0), 0x80);
+ p = ioremap(pci_resource_start(dev, 0), 0x80);
switch (dev->device & 0xfff8) {
case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */
@@ -3841,6 +4034,36 @@ pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
return 0;
}
+/* Added for EKF Intel i960 serial boards */
+static int
+#ifndef MODULE
+__init
+#endif
+pci_inteli960ni_fn(struct pci_dev *dev,
+ struct pci_board *board,
+ int enable)
+{
+ unsigned long oldval;
+
+ if (!(board->subdevice & 0x1000))
+ return(-1);
+
+ if (!enable) /* is there something to deinit? */
+ return(0);
+
+#ifdef SERIAL_DEBUG_PCI
+ printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n",
+ (unsigned long) board->subdevice);
+#endif
+ /* is firmware started? */
+ pci_read_config_dword(dev, 0x44, (void*) &oldval);
+ if (oldval == 0x00001000L) { /* RESET value */
+ printk(KERN_DEBUG "Local i960 firmware missing");
+ return(-1);
+ }
+ return(0);
+}
+
/*
* This is the configuration table for all of the PCI serial boards
@@ -3851,8 +4074,9 @@ static struct pci_board pci_boards[] __initdata = {
* Vendor ID, Device ID,
* Subvendor ID, Subdevice ID,
* PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
- * Offset to get to next UART's registers
- * Register shift to use for memory-mapped I/O
+ * Offset to get to next UART's registers,
+ * Register shift to use for memory-mapped I/O,
+ * Initialization function, first UART offset
*/
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
PCI_SUBVENDOR_ID_CONNECT_TECH,
@@ -3942,6 +4166,10 @@ static struct pci_board pci_boards[] __initdata = {
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
PCI_ANY_ID, PCI_ANY_ID,
SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 },
+ /* VScom SPCOM800, from sl@s.pl */
+ { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2, 8, 921600 },
{ PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
PCI_SUBVENDOR_ID_KEYSPAN,
PCI_SUBDEVICE_ID_KEYSPAN_SX2,
@@ -3979,6 +4207,12 @@ static struct pci_board pci_boards[] __initdata = {
PCI_SUBVENDOR_ID_CHASE_PCIRAS,
PCI_SUBDEVICE_ID_CHASE_PCIRAS8,
SPCI_FL_BASE2, 8, 460800 },
+ /* Megawolf Romulus PCI Serial Card, from Mike Hudson */
+ /* (Exoray@isys.ca) */
+ { PCI_VENDOR_ID_PLX, PCI_VENDOR_ID_PLX_ROMULUS,
+ 0x10b5, 0x106a,
+ SPCI_FL_BASE2, 4, 921600,
+ 0x20, 2, pci_plx9050_fn, 0x03 },
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
PCI_ANY_ID, PCI_ANY_ID,
SPCI_FL_BASE1, 4, 115200 },
@@ -4164,7 +4398,7 @@ static struct pci_board pci_boards[] __initdata = {
PCI_ANY_ID, PCI_ANY_ID,
SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
0, 0, pci_siig20x_fn },
- /* Computone devices submitted by Doug McNash dougm@computone.com */
+ /* Computone devices submitted by Doug McNash dmcnash@computone.com */
{ PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
SPCI_FL_BASE0, 4, 921600, /* IOMEM */
@@ -4198,6 +4432,15 @@ static struct pci_board pci_boards[] __initdata = {
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
PCI_ANY_ID, PCI_ANY_ID,
SPCI_FL_BASE0, 4, 921600 },
+ /* EKF addition for i960 Boards form EKF with serial port */
+ { PCI_VENDOR_ID_INTEL, 0x1960,
+ 0xE4BF, PCI_ANY_ID,
+ SPCI_FL_BASE0, 32, 921600, /* max 256 ports */
+ 8<<2, 2, pci_inteli960ni_fn, 0x10000},
+ /* RAStel 2 port modem, gerg@moreton.com.au */
+ { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT,
+ PCI_ANY_ID, PCI_ANY_ID,
+ SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
/*
* Untested PCI modems, sent in from various folks...
*/
@@ -4222,12 +4465,12 @@ static struct pci_board pci_boards[] __initdata = {
};
/*
- * Given a complete unknown PCI device, try to use some hueristics to
+ * Given a complete unknown PCI device, try to use some heuristics to
* guess what the configuration might be, based on the pitiful PCI
* serial specs. Returns 0 on success, 1 on failure.
*/
-static int _INLINE_ serial_guess_board(struct pci_dev *dev,
- struct pci_board *board)
+static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev,
+ struct pci_board *board)
{
int num_iomem = 0, num_port = 0, first_port = -1;
int i;
@@ -4282,13 +4525,6 @@ static void __init probe_serial_pci(void)
printk(KERN_DEBUG "Entered probe_serial_pci()\n");
#endif
- if (!pcibios_present()) {
-#ifdef SERIAL_DEBUG_PCI
- printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n");
-#endif
- return;
- }
-
pci_for_each_dev(dev) {
for (board = pci_boards; board->vendor; board++) {
if (board->vendor != (unsigned short) PCI_ANY_ID &&
@@ -4306,7 +4542,7 @@ static void __init probe_serial_pci(void)
break;
}
- if (board->vendor == 0 && serial_guess_board(dev, board))
+ if (board->vendor == 0 && serial_pci_guess_board(dev, board))
continue;
start_pci_pnp_board(dev, board);
@@ -4322,58 +4558,280 @@ static void __init probe_serial_pci(void)
#ifdef ENABLE_SERIAL_PNP
-static struct pci_board pnp_devices[] __initdata = {
- /* Motorola VoiceSURFR 56K Modem */
- { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+struct pnp_board {
+ unsigned short vendor;
+ unsigned short device;
+};
+
+static struct pnp_board pnp_devices[] __initdata = {
+ /* Archtek America Corp. */
+ /* Archtek SmartLink Modem 3334BT Plug & Play */
+ { ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
+ /* Anchor Datacomm BV */
+ /* SXPro 144 External Data Fax Modem Plug & Play */
+ { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) },
+ /* SXPro 288 External Data Fax Modem Plug & Play */
+ { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) },
/* Rockwell 56K ACF II Fax+Data+Voice Modem */
- { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT,
- 1, 115200 },
+ { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) },
/* AZT3005 PnP SOUND DEVICE */
- { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) },
/* Best Data Products Inc. Smart One 336F PnP Modem */
- { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
+ /* Boca Research */
+ /* Boca Complete Ofc Communicator 14.4 Data-FAX */
+ { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
/* Boca Research 33,600 ACF Modem */
- { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) },
+ /* Boca 33.6 Kbps Internal FD34FSVD */
+ { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) },
+ /* Boca 33.6 Kbps Internal FD34FSVD */
+ { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) },
+ /* Best Data Products Inc. Smart One 336F PnP Modem */
+ { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) },
+ /* Computer Peripherals Inc */
+ /* EuroViVa CommCenter-33.6 SP PnP */
+ { ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) },
+ /* Creative Labs */
+ /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
+ { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) },
+ /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
+ { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) },
+ /* Creative */
/* Creative Modem Blaster Flash56 DI5601-1 */
- { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) },
/* Creative Modem Blaster V.90 DI5660 */
- { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) },
+ /* FUJITSU */
+ /* Fujitsu 33600 PnP-I2 R Plug & Play */
+ { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) },
+ /* Fujitsu FMV-FX431 Plug & Play */
+ { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) },
+ /* Fujitsu 33600 PnP-I4 R Plug & Play */
+ { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) },
+ /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
+ { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) },
+ /* Archtek America Corp. */
+ /* Archtek SmartLink Modem 3334BT Plug & Play */
+ { ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) },
+ /* Hayes */
+ /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) },
+ /* Hayes Optima 336 V.34 + FAX + Voice PnP */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) },
+ /* Hayes Optima 336B V.34 + FAX + Voice PnP */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) },
+ /* Hayes Accura 56K Ext Fax Modem PnP */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) },
+ /* Hayes Accura 56K Ext Fax Modem PnP */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) },
+ /* Hayes Accura 56K Fax Modem PnP */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) },
+ /* Hayes 288, V.34 + FAX */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) },
+ /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
+ { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) },
+ /* IBM */
+ /* IBM Thinkpad 701 Internal Modem Voice */
+ { ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) },
+ /* Intertex */
+ /* Intertex 28k8 33k6 Voice EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) },
+ /* Intertex 33k6 56k Voice EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) },
+ /* Intertex 28k8 33k6 Voice SP EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) },
+ /* Intertex 33k6 56k Voice SP EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) },
+ /* Intertex 28k8 33k6 Voice SP INT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) },
+ /* Intertex 28k8 33k6 Voice SP EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) },
+ /* Intertex 33k6 56k Voice SP EXT PnP */
+ { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) },
+ /* Kortex International */
+ /* KORTEX 28800 Externe PnP */
+ { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) },
+ /* KXPro 33.6 Vocal ASVD PnP */
+ { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) },
+ /* Lasat */
+ /* LASAT Internet 33600 PnP */
+ { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) },
+ /* Lasat Safire 560 PnP */
+ { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) },
+ /* Lasat Safire 336 PnP */
+ { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) },
+ /* Microcom, Inc. */
+ /* Microcom TravelPorte FAST V.34 Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) },
+ /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) },
+ /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) },
+ /* Microcom DeskPorte 28.8P Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) },
+ /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
+ /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
+ /* Microcom DeskPorte 28.8S Internal Plug & Play */
+ { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) },
+ /* Motorola */
+ /* Motorola BitSURFR Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) },
+ /* Motorola TA210 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) },
+ /* Motorola HMTA 200 (ISDN) Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) },
+ /* Motorola BitSURFR Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) },
+ /* Motorola Lifestyle 28.8 Internal */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) },
+ /* Motorola V.3400 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) },
+ /* Motorola Lifestyle 28.8 V.34 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) },
+ /* Motorola Power 28.8 V.34 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) },
+ /* Motorola ModemSURFR External 28.8 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) },
+ /* Motorola Premier 33.6 Desktop Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) },
+ /* Motorola VoiceSURFR 56K External PnP */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) },
+ /* Motorola ModemSURFR 56K External PnP */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) },
+ /* Motorola ModemSURFR 56K Internal PnP */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) },
+ /* Motorola ModemSURFR Internal 28.8 Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) },
+ /* Motorola Premier 33.6 Internal Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) },
+ /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) },
+ /* Motorola VoiceSURFR 56K Internal PnP */
+ { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) },
+ /* Com 1 */
+ /* Deskline K56 Phone System PnP */
+ { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) },
+ /* PC Rider K56 Phone System PnP */
+ { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) },
/* Pace 56 Voice Internal Plug & Play Modem */
- { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* SupraExpress 28.8 Data/Fax PnP modem */
- { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* US Robotics Sporster 33600 Modem */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* U.S. Robotics 56K FAX INT */
- { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* Viking 56K FAX INT */
- { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
-
- /* These ID's are taken from M$ documentation */
- /* Compaq 14400 Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
- /* Compaq 2400/9600 Modem */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) },
+ /* Generic */
/* Generic standard PC COM port */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) },
/* Generic 16550A-compatible COM port */
- { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501), 0, 0,
- SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) },
+ /* Compaq 14400 Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) },
+ /* Compaq 2400/9600 Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) },
+ /* Dial-Up Networking Serial Cable between 2 PCs */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) },
+ /* Dial-Up Networking Parallel Cable between 2 PCs */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) },
+ /* Standard 9600 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) },
+ /* Standard 14400 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) },
+ /* Standard 28800 bps Modem*/
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) },
+ /* Standard Modem*/
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) },
+ /* Standard 9600 bps Modem*/
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) },
+ /* Standard 14400 bps Modem*/
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) },
+ /* Standard 28800 bps Modem*/
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) },
+ /* Standard Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) },
+ /* Standard 9600 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) },
+ /* Standard 14400 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) },
+ /* Standard 28800 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) },
+ /* Standard Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) },
+ /* Standard 9600 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) },
+ /* Standard 14400 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) },
+ /* Standard 28800 bps Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) },
+ /* Standard Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) },
+ /* Standard PCMCIA Card Modem */
+ { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) },
+ /* Rockwell */
+ /* Modular Technology */
+ /* Rockwell 33.6 DPF Internal PnP */
+ /* Modular Technology 33.6 Internal PnP */
+ { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) },
+ /* Kortex International */
+ /* KORTEX 14400 Externe PnP */
+ { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) },
+ /* Viking Components, Inc */
+ /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
+ { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) },
+ /* Rockwell */
+ /* British Telecom */
+ /* Modular Technology */
+ /* Rockwell 33.6 DPF External PnP */
+ /* BT Prologue 33.6 External PnP */
+ /* Modular Technology 33.6 External PnP */
+ { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) },
+ /* Viking 56K FAX INT */
+ { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) },
+ /* SupraExpress 28.8 Data/Fax PnP modem */
+ { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) },
+ /* SupraExpress 33.6 Data/Fax PnP modem */
+ { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) },
+ /* SupraExpress 33.6 Data/Fax PnP modem */
+ { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) },
+ /* SupraExpress 33.6 Data/Fax PnP modem */
+ { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) },
+ /* Phoebe Micro */
+ /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
+ { ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) },
+ /* Archtek America Corp. */
+ /* Archtek SmartLink Modem 3334BT Plug & Play */
+ { ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) },
+ /* 3Com Corp. */
+ /* Gateway Telepath IIvi 33.6 */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) },
+ /* Sportster Vi 14.4 PnP FAX Voicemail */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) },
+ /* U.S. Robotics 33.6K Voice INT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) },
+ /* U.S. Robotics 33.6K Voice EXT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) },
+ /* U.S. Robotics 33.6K Voice INT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) },
+ /* U.S. Robotics 56K Voice INT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) },
+ /* U.S. Robotics 56K Voice EXT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) },
+ /* U.S. Robotics 56K FAX INT */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) },
+ /* U.S. Robotics 56K Voice INT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) },
+ /* U.S. Robotics 56K Voice EXT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) },
+ /* U.S. Robotics 56K Voice INT PnP */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) },
+ /* U.S. Robotics 56K Message */
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) },
+ /* U.S. Robotics 56K FAX EXT PnP*/
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) },
+ /* U.S. Robotics 56K FAX INT PnP*/
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) },
+ /* U.S. Robotics 56K Voice EXT PnP*/
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) },
+ /* U.S. Robotics 56K Voice INT PnP*/
+ { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) },
{ 0, }
};
@@ -4395,10 +4853,80 @@ static void inline avoid_irq_share(struct pci_dev *dev)
irq->map = map;
}
+static char *modem_names[] __initdata = {
+ "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
+ "56K", "56k", "K56", "33.6", "28.8", "14.4",
+ "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
+ "33600", "28800", "14400", "V.90", "V.34", "V.32", 0
+};
+
+static int __init check_name(char *name)
+{
+ char **tmp = modem_names;
+
+ while (*tmp) {
+ if (strstr(name, *tmp))
+ return 1;
+ tmp++;
+ }
+ return 0;
+}
+
+static int inline check_compatible_id(struct pci_dev *dev)
+{
+ int i;
+ for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++)
+ if ((dev->vendor_compatible[i] ==
+ ISAPNP_VENDOR('P', 'N', 'P')) &&
+ (swab16(dev->device_compatible[i]) >= 0xc000) &&
+ (swab16(dev->device_compatible[i]) <= 0xdfff))
+ return 0;
+ return 1;
+}
+
+/*
+ * Given a complete unknown ISA PnP device, try to use some heuristics to
+ * detect modems. Currently use such heuristic set:
+ * - dev->name or dev->bus->name must contain "modem" substring;
+ * - device must have only one IO region (8 byte long) with base adress
+ * 0x2e8, 0x3e8, 0x2f8 or 0x3f8.
+ *
+ * Such detection looks very ugly, but can detect at least some of numerous
+ * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[]
+ * table.
+ */
+static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev,
+ struct pci_board *board)
+{
+ struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata;
+ struct isapnp_resources *resa;
+
+ if (!(check_name(dev->name) || check_name(dev->bus->name)) &&
+ !(check_compatible_id(dev)))
+ return 1;
+
+ if (!res || res->next)
+ return 1;
+
+ for (resa = res->alt; resa; resa = resa->alt) {
+ struct isapnp_port *port;
+ for (port = res->port; port; port = port->next)
+ if ((port->size == 8) &&
+ ((port->min == 0x2f8) ||
+ (port->min == 0x3f8) ||
+ (port->min == 0x2e8) ||
+ (port->min == 0x3e8)))
+ return 0;
+ }
+
+ return 1;
+}
+
static void __init probe_serial_pnp(void)
{
struct pci_dev *dev = NULL;
- struct pci_board *board;
+ struct pnp_board *pnp_board;
+ struct pci_board board;
#ifdef SERIAL_DEBUG_PNP
printk("Entered probe_serial_pnp()\n");
@@ -4410,13 +4938,35 @@ static void __init probe_serial_pnp(void)
return;
}
- for (board = pnp_devices; board->vendor; board++) {
- while ((dev = isapnp_find_dev(NULL, board->vendor,
- board->device, dev))) {
- if (board->flags & SPCI_FL_NO_SHIRQ)
- avoid_irq_share(dev);
- start_pci_pnp_board(dev, board);
- }
+ isapnp_for_each_dev(dev) {
+ if (dev->active)
+ continue;
+
+ memset(&board, 0, sizeof(board));
+ board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT;
+ board.num_ports = 1;
+ board.base_baud = 115200;
+
+ for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++)
+ if ((dev->vendor == pnp_board->vendor) &&
+ (dev->device == pnp_board->device))
+ break;
+
+ if (pnp_board->vendor) {
+ board.vendor = pnp_board->vendor;
+ board.device = pnp_board->device;
+ /* Special case that's more efficient to hardcode */
+ if ((board.vendor == ISAPNP_VENDOR('A', 'K', 'Y') &&
+ board.device == ISAPNP_DEVICE(0x1021)))
+ board.flags |= SPCI_FL_NO_SHIRQ;
+ } else {
+ if (serial_pnp_guess_board(dev, &board))
+ continue;
+ }
+
+ if (board.flags & SPCI_FL_NO_SHIRQ)
+ avoid_irq_share(dev);
+ start_pci_pnp_board(dev, &board);
}
#ifdef SERIAL_DEBUG_PNP
@@ -4478,7 +5028,7 @@ int __init rs_init(void)
#if (LINUX_VERSION_CODE > 0x20100)
serial_driver.driver_name = "serial";
#endif
-#ifdef CONFIG_DEVFS_FS
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
serial_driver.name = "tts/%d";
#else
serial_driver.name = "ttyS";
@@ -4526,7 +5076,7 @@ int __init rs_init(void)
* major number and the subtype code.
*/
callout_driver = serial_driver;
-#ifdef CONFIG_DEVFS_FS
+#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
callout_driver.name = "cua/%d";
#else
callout_driver.name = "cua";
@@ -4616,14 +5166,25 @@ int register_serial(struct serial_struct *req)
unsigned long flags;
struct serial_state *state;
struct async_struct *info;
+ unsigned long port;
+
+ port = req->port;
+ if (HIGH_BITS_OFFSET)
+ port += req->port_high << HIGH_BITS_OFFSET;
save_flags(flags); cli();
for (i = 0; i < NR_PORTS; i++) {
- if ((rs_table[i].port == req->port) &&
+ if ((rs_table[i].port == port) &&
(rs_table[i].iomem_base == req->iomem_base))
break;
}
if (i == NR_PORTS) {
+ for (i = 4; i < NR_PORTS; i++)
+ if ((rs_table[i].type == PORT_UNKNOWN) &&
+ (rs_table[i].count == 0))
+ break;
+ }
+ if (i == NR_PORTS) {
for (i = 0; i < NR_PORTS; i++)
if ((rs_table[i].type == PORT_UNKNOWN) &&
(rs_table[i].count == 0))
@@ -4637,11 +5198,11 @@ int register_serial(struct serial_struct *req)
if (rs_table[i].count) {
restore_flags(flags);
printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
- "device already open\n", i, req->port, req->irq);
+ "device already open\n", i, port, req->irq);
return -1;
}
state->irq = req->irq;
- state->port = req->port;
+ state->port = port;
state->flags = req->flags;
state->io_type = req->io_type;
state->iomem_base = req->iomem_base;
@@ -4649,7 +5210,7 @@ int register_serial(struct serial_struct *req)
if (req->baud_base)
state->baud_base = req->baud_base;
if ((info = state->info) != NULL) {
- info->port = req->port;
+ info->port = port;
info->flags = req->flags;
info->io_type = req->io_type;
info->iomem_base = req->iomem_base;
@@ -4722,10 +5283,10 @@ void rs_fini(void)
timer_table[RS_TIMER].expires = 0;
remove_bh(SERIAL_BH);
if ((e1 = tty_unregister_driver(&serial_driver)))
- printk("SERIAL: failed to unregister serial driver (%d)\n",
+ printk("serial: failed to unregister serial driver (%d)\n",
e1);
if ((e2 = tty_unregister_driver(&callout_driver)))
- printk("SERIAL: failed to unregister callout driver (%d)\n",
+ printk("serial: failed to unregister callout driver (%d)\n",
e2);
restore_flags(flags);
@@ -4734,8 +5295,15 @@ void rs_fini(void)
rs_table[i].info = NULL;
kfree_s(info, sizeof(struct async_struct));
}
- if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port)
- release_region(rs_table[i].port, 8);
+ if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) {
+#ifdef CONFIG_SERIAL_RSA
+ if (rs_table[i].type == PORT_RSA)
+ release_region(rs_table[i].port +
+ UART_RSA_BASE, 16);
+ else
+#endif
+ release_region(rs_table[i].port, 8);
+ }
#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
if (rs_table[i].iomem_base)
iounmap(rs_table[i].iomem_base);
@@ -4882,9 +5450,6 @@ static int __init serial_console_setup(struct console *co, char *options)
int cflag = CREAD | HUPCL | CLOCAL;
int quot = 0;
char *s;
-#if defined(CONFIG_KDB)
- extern int kdb_port;
-#endif
if (options) {
baud = simple_strtoul(options, NULL, 10);
@@ -4988,14 +5553,6 @@ static int __init serial_console_setup(struct console *co, char *options)
if (serial_in(info, UART_LSR) == 0xff)
return -1;
-#if defined(CONFIG_KDB)
- /*
- * Remember I/O port for kdb
- */
- if (kdb_port == 0 )
- kdb_port = ser->port;
-#endif /* CONFIG_KDB */
-
return 0;
}
@@ -5024,6 +5581,6 @@ void __init serial_console_init(void)
/*
Local variables:
- compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
+ compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c"
End:
*/
diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c
index 05bfcb607..b51e91557 100644
--- a/drivers/char/sh-sci.c
+++ b/drivers/char/sh-sci.c
@@ -5,6 +5,7 @@
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
* Copyright (C) 1999, 2000 Niibe Yutaka
* Copyright (C) 2000 Sugioka Toshinobu
+ * Modified to support multiple serial ports. Stuart Menefy (May 2000).
*
* TTY code is based on sx.c (Specialix SX driver) by:
*
@@ -31,7 +32,9 @@
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/delay.h>
+#ifdef CONFIG_SERIAL_CONSOLE
#include <linux/console.h>
+#endif
#include <asm/system.h>
#include <asm/io.h>
@@ -40,15 +43,23 @@
#include <asm/bitops.h>
#include <linux/generic_serial.h>
-#include "sh-sci.h"
#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
static void gdb_detach(void);
+static int in_gdb = 1;
+#define IN_GDB in_gdb
#endif
+#include "sh-sci.h"
-struct sci_port sci_ports[1];
+#ifdef CONFIG_SERIAL_CONSOLE
+static struct console sercons;
+static struct sci_port* sercons_port;
+static int sercons_baud;
+#endif
/* Function prototypes */
+static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag);
+static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag);
static void sci_disable_tx_interrupts(void *ptr);
static void sci_enable_tx_interrupts(void *ptr);
static void sci_disable_rx_interrupts(void *ptr);
@@ -63,9 +74,10 @@ static int sci_init_drivers(void);
static struct tty_driver sci_driver, sci_callout_driver;
-#define SCI_NPORTS 1
+static struct sci_port sci_ports[SCI_NPORTS] = SCI_INIT;
static struct tty_struct *sci_table[SCI_NPORTS] = { NULL, };
-static struct termios *sci_termios[2]; /* nomal, locked */
+static struct termios *sci_termios[SCI_NPORTS];
+static struct termios *sci_termios_locked[SCI_NPORTS];
int sci_refcount;
int sci_debug = 0;
@@ -88,6 +100,63 @@ static struct real_driver sci_real_driver = {
NULL
};
+#if defined(SCI_ONLY) || defined(SCI_AND_SCIF)
+static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag)
+{
+}
+#endif
+
+#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
+#if defined(__sh3__)
+/* For SH7709, SH7709A, SH7729 */
+static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag)
+{
+ unsigned int fcr_val = 0;
+
+ {
+ unsigned short data;
+
+ /* We need to set SCPCR to enable RTS/CTS */
+ data = ctrl_inw(SCPCR);
+ /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
+ ctrl_outw(data&0x0fcf, SCPCR);
+ }
+ if (cflag & CRTSCTS)
+ fcr_val |= SCFCR_MCE;
+ else {
+ unsigned short data;
+
+ /* We need to set SCPCR to enable RTS/CTS */
+ data = ctrl_inw(SCPCR);
+ /* Clear out SCP7MD1,0, SCP4MD1,0,
+ Set SCP6MD1,0 = {01} (output) */
+ ctrl_outw((data&0x0fcf)|0x1000, SCPCR);
+
+ data = ctrl_inb(SCPDR);
+ /* Set /RTS2 (bit6) = 0 */
+ ctrl_outb(data&0xbf, SCPDR);
+ }
+ sci_out(port, SCFCR, fcr_val);
+}
+
+#else
+
+/* For SH7750 */
+static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag)
+{
+ unsigned int fcr_val = 0;
+
+ if (cflag & CRTSCTS) {
+ fcr_val |= SCFCR_MCE;
+ } else {
+ ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
+ }
+ sci_out(port, SCFCR, fcr_val);
+}
+
+#endif
+#endif /* SCIF_ONLY || SCI_AND_SCIF */
+
static void sci_setsignals(struct sci_port *port, int dtr, int rts)
{
/* This routine is used for seting signals of: DTR, DCD, CTS/RTS */
@@ -112,11 +181,11 @@ static int sci_getsignals(struct sci_port *port)
*/
}
-static void sci_set_baud(struct sci_port *port)
+static void sci_set_baud(struct sci_port *port, int baud)
{
int t;
- switch (port->gs.baud) {
+ switch (baud) {
case 0:
t = -1;
break;
@@ -136,7 +205,7 @@ static void sci_set_baud(struct sci_port *port)
t = BPS_38400;
break;
default:
- printk(KERN_INFO "sci: unsupported baud rate: %d, use 115200 instead.\n", port->gs.baud);
+ printk(KERN_INFO "sci: unsupported baud rate: %d, use 115200 instead.\n", baud);
case 115200:
t = BPS_115200;
break;
@@ -145,93 +214,57 @@ static void sci_set_baud(struct sci_port *port)
if (t > 0) {
sci_setsignals (port, 1, -1);
if(t >= 256) {
- ctrl_out((ctrl_in(SCSMR) & ~3) | 1, SCSMR);
+ sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
t >>= 2;
}
- ctrl_outb(t, SCBRR);
- ctrl_outw(0xa400, RFCR); /* Refresh counter clear */
- while (ctrl_inw(RFCR) < WAIT_RFCR_COUNTER)
- ;
+ sci_out(port, SCBRR, t);
+ udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
} else {
sci_setsignals (port, 0, -1);
}
}
-static void sci_set_termios_cflag(struct sci_port *port)
+static void sci_set_termios_cflag(struct sci_port *port, int cflag, int baud)
{
- unsigned short status;
- unsigned short smr_val;
-#if defined(CONFIG_SH_SCIF_SERIAL)
- unsigned short fcr_val=6; /* TFRST=1, RFRST=1 */
-#endif
+ unsigned int status;
+ unsigned int smr_val;
do
- status = ctrl_in(SC_SR);
- while (!(status & SCI_TEND));
+ status = sci_in(port, SCxSR);
+ while (!(status & SCxSR_TEND(port)));
- port->old_cflag = port->gs.tty->termios->c_cflag;
+ sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
- ctrl_out(0x00, SCSCR); /* TE=0, RE=0, CKE1=0 */
-#if defined(CONFIG_SH_SCIF_SERIAL)
- ctrl_out(fcr_val, SCFCR);
- fcr_val = 0;
-#endif
+ if (port->type == PORT_SCIF) {
+ sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+ }
- smr_val = ctrl_in(SCSMR) & 3;
- if ((port->gs.tty->termios->c_cflag & CSIZE) == CS7)
+ smr_val = sci_in(port, SCSMR) & 3;
+ if ((cflag & CSIZE) == CS7)
smr_val |= 0x40;
- if (C_PARENB(port->gs.tty))
+ if (cflag & PARENB)
smr_val |= 0x20;
- if (C_PARODD(port->gs.tty))
+ if (cflag & PARODD)
smr_val |= 0x10;
- if (C_CSTOPB(port->gs.tty))
+ if (cflag & CSTOPB)
smr_val |= 0x08;
- ctrl_out(smr_val, SCSMR);
-
-#if defined(CONFIG_SH_SCIF_SERIAL)
-#if defined(__sh3__)
- { /* For SH7709, SH7709A, SH7729 */
- unsigned short data;
-
- /* We need to set SCPCR to enable RTS/CTS */
- data = ctrl_inw(SCPCR);
- /* Clear out SCP7MD1,0, SCP6MD1,0, SCP4MD1,0*/
- ctrl_outw(data&0x0fcf, SCPCR);
- }
-#endif
- if (C_CRTSCTS(port->gs.tty))
- fcr_val |= 0x08;
- else {
-#if defined(__sh3__)
- unsigned short data;
-
- /* We need to set SCPCR to enable RTS/CTS */
- data = ctrl_inw(SCPCR);
- /* Clear out SCP7MD1,0, SCP4MD1,0,
- Set SCP6MD1,0 = {01} (output) */
- ctrl_outw((data&0x0fcf)|0x1000, SCPCR);
+ sci_out(port, SCSMR, smr_val);
- data = ctrl_inb(SCPDR);
- /* Set /RTS2 (bit6) = 0 */
- ctrl_outb(data&0xbf, SCPDR);
-#elif defined(__SH4__)
- ctrl_outw(0x0080, SCSPTR); /* Set RTS = 1 */
-#endif
- }
- ctrl_out(fcr_val, SCFCR);
-#endif
+ port->init_pins(port, cflag);
- sci_set_baud(port);
- ctrl_out(SCSCR_INIT, SCSCR); /* TIE=0,RIE=0,TE=1,RE=1 */
- sci_enable_rx_interrupts(port);
+ sci_set_baud(port, baud);
+ sci_out(port, SCSCR, SCSCR_INIT(port));
}
static int sci_set_real_termios(void *ptr)
{
struct sci_port *port = ptr;
- if (port->old_cflag != port->gs.tty->termios->c_cflag)
- sci_set_termios_cflag(port);
+ if (port->old_cflag != port->gs.tty->termios->c_cflag) {
+ port->old_cflag = port->gs.tty->termios->c_cflag;
+ sci_set_termios_cflag(port, port->old_cflag, port->gs.baud);
+ sci_enable_rx_interrupts(port);
+ }
/* Tell line discipline whether we will do input cooking */
if (I_OTHER(port->gs.tty))
@@ -265,27 +298,27 @@ static void sci_transmit_chars(struct sci_port *port)
unsigned short ctrl;
unsigned char c;
- status = ctrl_in(SC_SR);
- if (!(status & SCI_TD_E)) {
+ status = sci_in(port, SCxSR);
+ if (!(status & SCxSR_TDxE(port))) {
save_and_cli(flags);
- ctrl = ctrl_in(SCSCR);
+ ctrl = sci_in(port, SCSCR);
if (port->gs.xmit_cnt == 0) {
ctrl &= ~SCI_CTRL_FLAGS_TIE;
port->gs.flags &= ~GS_TX_INTEN;
} else
ctrl |= SCI_CTRL_FLAGS_TIE;
- ctrl_out(ctrl, SCSCR);
+ sci_out(port, SCSCR, ctrl);
restore_flags(flags);
return;
}
while (1) {
count = port->gs.xmit_cnt;
-#if defined(CONFIG_SH_SCIF_SERIAL)
- txroom = 16 - (ctrl_inw(SCFDR)>>8);
-#else
- txroom = (ctrl_in(SC_SR)&SCI_TD_E)?1:0;
-#endif
+ if (port->type == PORT_SCIF) {
+ txroom = 16 - (sci_in(port, SCFDR)>>8);
+ } else {
+ txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
+ }
if (count > txroom)
count = txroom;
@@ -299,9 +332,9 @@ static void sci_transmit_chars(struct sci_port *port)
for (i=0; i<count; i++) {
c = port->gs.xmit_buf[port->gs.xmit_tail + i];
- ctrl_outb(c, SC_TDR);
+ sci_out(port, SCxTDR, c);
}
- ctrl_out(SCI_TD_E_CLEAR, SC_SR);
+ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
/* Update the kernel buffer end */
port->gs.xmit_tail = (port->gs.xmit_tail + count) & (SERIAL_XMIT_SIZE-1);
@@ -319,18 +352,18 @@ static void sci_transmit_chars(struct sci_port *port)
}
save_and_cli(flags);
- ctrl = ctrl_in(SCSCR);
+ ctrl = sci_in(port, SCSCR);
if (port->gs.xmit_cnt == 0) {
ctrl &= ~SCI_CTRL_FLAGS_TIE;
port->gs.flags &= ~GS_TX_INTEN;
} else {
-#if defined(CONFIG_SH_SCIF_SERIAL)
- ctrl_in(SC_SR); /* Dummy read */
- ctrl_out(SCI_TD_E_CLEAR, SC_SR);
-#endif
+ if (port->type == PORT_SCIF) {
+ sci_in(port, SCxSR); /* Dummy read */
+ sci_out(port, SCxSR, SCIF_TDFE);
+ }
ctrl |= SCI_CTRL_FLAGS_TIE;
}
- ctrl_out(ctrl, SCSCR);
+ sci_out(port, SCSCR, ctrl);
restore_flags(flags);
}
@@ -341,17 +374,17 @@ static inline void sci_receive_chars(struct sci_port *port)
int copied=0;
unsigned short status;
- status = ctrl_in(SC_SR);
- if (!(status & SCI_RD_F))
+ status = sci_in(port, SCxSR);
+ if (!(status & SCxSR_RDxF(port)))
return;
tty = port->gs.tty;
while (1) {
-#if defined(CONFIG_SH_SCIF_SERIAL)
- count = ctrl_inw(SCFDR)&0x001f;
-#else
- count = (ctrl_in(SC_SR)&SCI_RD_F)?1:0;
-#endif
+ if (port->type == PORT_SCIF) {
+ count = sci_in(port, SCFDR)&0x001f;
+ } else {
+ count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
+ }
/* Don't copy more bytes than there is room for in the buffer */
if (tty->flip.count + count > TTY_FLIPBUF_SIZE)
@@ -362,9 +395,9 @@ static inline void sci_receive_chars(struct sci_port *port)
break;
for (i=0; i<count; i++)
- tty->flip.char_buf_ptr[i] = ctrl_inb(SC_RDR);
- ctrl_in(SC_SR); /* dummy read */
- ctrl_out(SCI_RDRF_CLEAR, SC_SR);
+ tty->flip.char_buf_ptr[i] = sci_in(port, SCxRDR);
+ sci_in(port, SCxSR); /* dummy read */
+ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count);
@@ -384,16 +417,13 @@ static inline void sci_receive_chars(struct sci_port *port)
static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
struct sci_port *port = ptr;
- unsigned long flags;
if (port->gs.flags & GS_ACTIVE)
if (!(port->gs.flags & SCI_RX_THROTTLE)) {
sci_receive_chars(port);
return;
}
- save_and_cli(flags);
- ctrl_out(ctrl_in(SCSCR) & ~SCI_CTRL_FLAGS_RIE, SCSCR);
- restore_flags(flags);
+ sci_disable_rx_interrupts(port);
}
static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
@@ -403,19 +433,17 @@ static void sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
if (port->gs.flags & GS_ACTIVE)
sci_transmit_chars(port);
else {
- unsigned long flags;
-
- save_and_cli(flags);
- ctrl_out(ctrl_in(SCSCR) & ~SCI_CTRL_FLAGS_TIE, SCSCR);
- restore_flags(flags);
+ sci_disable_tx_interrupts(port);
}
}
static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
+ struct sci_port *port = ptr;
+
/* Handle errors */
- if (ctrl_in(SC_SR) & SCI_ERRORS)
- ctrl_out(SCI_ERROR_CLEAR, SC_SR);
+ if (sci_in(port, SCxSR) & SCxSR_ERRORS(port))
+ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
/* Kick the transmission */
sci_tx_interrupt(irq, ptr, regs);
@@ -428,14 +456,15 @@ static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
static void sci_disable_tx_interrupts(void *ptr)
{
+ struct sci_port *port = ptr;
unsigned long flags;
unsigned short ctrl;
/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
save_and_cli(flags);
- ctrl = ctrl_in(SCSCR);
+ ctrl = sci_in(port, SCSCR);
ctrl &= ~SCI_CTRL_FLAGS_TIE;
- ctrl_out(ctrl, SCSCR);
+ sci_out(port, SCSCR, ctrl);
restore_flags(flags);
}
@@ -443,34 +472,36 @@ static void sci_enable_tx_interrupts(void *ptr)
{
struct sci_port *port = ptr;
- disable_irq(SCI_TXI_IRQ);
+ disable_irq(port->irqs[SCIx_TXI_IRQ]);
sci_transmit_chars(port);
- enable_irq(SCI_TXI_IRQ);
+ enable_irq(port->irqs[SCIx_TXI_IRQ]);
}
static void sci_disable_rx_interrupts(void * ptr)
{
+ struct sci_port *port = ptr;
unsigned long flags;
unsigned short ctrl;
/* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
save_and_cli(flags);
- ctrl = ctrl_in(SCSCR);
+ ctrl = sci_in(port, SCSCR);
ctrl &= ~SCI_CTRL_FLAGS_RIE;
- ctrl_out(ctrl, SCSCR);
+ sci_out(port, SCSCR, ctrl);
restore_flags(flags);
}
static void sci_enable_rx_interrupts(void * ptr)
{
+ struct sci_port *port = ptr;
unsigned long flags;
unsigned short ctrl;
/* Set RIE (Receive Interrupt Enable) bit in SCSCR */
save_and_cli(flags);
- ctrl = ctrl_in(SCSCR);
+ ctrl = sci_in(port, SCSCR);
ctrl |= SCI_CTRL_FLAGS_RIE;
- ctrl_out(ctrl, SCSCR);
+ sci_out(port, SCSCR, ctrl);
restore_flags(flags);
}
@@ -482,11 +513,13 @@ static int sci_get_CD(void * ptr)
static int sci_chars_in_buffer(void * ptr)
{
-#if defined(CONFIG_SH_SCIF_SERIAL)
- return (ctrl_inw(SCFDR) >> 8) + ((ctrl_in(SC_SR) & SCI_TEND)? 0: 1);
-#else
- return (ctrl_in(SC_SR) & SCI_TEND)? 0: 1;
-#endif
+ struct sci_port *port = ptr;
+
+ if (port->type == PORT_SCIF) {
+ return (sci_in(port, SCFDR) >> 8) + ((sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1);
+ } else {
+ return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1;
+ }
}
static void sci_shutdown_port(void * ptr)
@@ -551,6 +584,15 @@ static int sci_open(struct tty_struct * tty, struct file * filp)
sci_set_real_termios(port);
}
+#ifdef CONFIG_SERIAL_CONSOLE
+ if (sercons.cflag && sercons.index == line) {
+ tty->termios->c_cflag = sercons.cflag;
+ port->gs.baud = sercons_baud;
+ sercons.cflag = 0;
+ sci_set_real_termios(port);
+ }
+#endif
+
sci_enable_rx_interrupts(port);
port->gs.session = current->session;
@@ -665,6 +707,25 @@ static void sci_unthrottle(struct tty_struct * tty)
return;
}
+#ifdef CONFIG_PROC_FS
+static int sci_read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ int i;
+ struct sci_port *port;
+ int len = 0;
+
+ len += sprintf(page, "serinfo:1.0\n");
+ for (i = 0; i < SCI_NPORTS && len < 4000; i++) {
+ port = &sci_ports[i];
+ len += sprintf(page+len, "%d: uart:%s address: %08x\n", i,
+ (port->type == PORT_SCI) ? "SCI" : "SCIF",
+ port->base);
+ }
+ return len;
+}
+#endif
+
/* ********************************************************************** *
* Here are the initialization routines. *
* ********************************************************************** */
@@ -678,20 +739,19 @@ static int sci_init_drivers(void)
sci_driver.magic = TTY_DRIVER_MAGIC;
sci_driver.driver_name = "serial";
sci_driver.name = "ttyS";
- sci_driver.major = TTY_MAJOR;
+ sci_driver.major = SCI_MAJOR;
sci_driver.minor_start = SCI_MINOR_START;
- sci_driver.num = 1;
+ sci_driver.num = SCI_NPORTS;
sci_driver.type = TTY_DRIVER_TYPE_SERIAL;
sci_driver.subtype = SERIAL_TYPE_NORMAL;
sci_driver.init_termios = tty_std_termios;
sci_driver.init_termios.c_cflag =
- B115200 | CS8 | CREAD | HUPCL | CLOCAL | CRTSCTS;
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL | CRTSCTS;
sci_driver.flags = TTY_DRIVER_REAL_RAW;
sci_driver.refcount = &sci_refcount;
sci_driver.table = sci_table;
- sci_driver.termios = &sci_termios[0];
- sci_driver.termios_locked = &sci_termios[1];
- sci_termios[0] = sci_termios[1] = NULL;
+ sci_driver.termios = sci_termios;
+ sci_driver.termios_locked = sci_termios_locked;
sci_driver.open = sci_open;
sci_driver.close = gs_close;
@@ -708,11 +768,15 @@ static int sci_init_drivers(void)
sci_driver.stop = gs_stop;
sci_driver.start = gs_start;
sci_driver.hangup = gs_hangup;
+#ifdef CONFIG_PROC_FS
+ sci_driver.read_proc = sci_read_proc;
+#endif
sci_callout_driver = sci_driver;
- sci_callout_driver.name = "cua";
- sci_callout_driver.major = TTYAUX_MAJOR;
+ sci_callout_driver.name = "cusc";
+ sci_callout_driver.major = SCI_MAJOR + 1;
sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+ sci_callout_driver.read_proc = NULL;
if ((error = tty_register_driver(&sci_driver))) {
printk(KERN_ERR "sci: Couldn't register SCI driver, error = %d\n",
@@ -726,16 +790,17 @@ static int sci_init_drivers(void)
return 1;
}
- port = &sci_ports[0];
- port->gs.callout_termios = tty_std_termios;
- port->gs.normal_termios = tty_std_termios;
- port->gs.magic = SCI_MAGIC;
- port->gs.close_delay = HZ/2;
- port->gs.closing_wait = 30 * HZ;
- port->gs.rd = &sci_real_driver;
- init_waitqueue_head(&port->gs.open_wait);
- init_waitqueue_head(&port->gs.close_wait);
- port->old_cflag = 0;
+ for (port = &sci_ports[0]; port < &sci_ports[SCI_NPORTS]; port++) {
+ port->gs.callout_termios = sci_callout_driver.init_termios;
+ port->gs.normal_termios = sci_driver.init_termios;
+ port->gs.magic = SCI_MAGIC;
+ port->gs.close_delay = HZ/2;
+ port->gs.closing_wait = 30 * HZ;
+ port->gs.rd = &sci_real_driver;
+ init_waitqueue_head(&port->gs.open_wait);
+ init_waitqueue_head(&port->gs.close_wait);
+ port->old_cflag = 0;
+ }
return 0;
}
@@ -744,26 +809,20 @@ int __init sci_init(void)
{
struct sci_port *port;
int i;
-
- for (i=SCI_ERI_IRQ; i<SCI_IRQ_END; i++)
- set_ipr_data(i, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY);
-
- port = &sci_ports[0];
-
- if (request_irq(SCI_ERI_IRQ, sci_er_interrupt, SA_INTERRUPT,
- "serial", port)) {
- printk(KERN_ERR "sci: Cannot allocate error irq.\n");
- return -ENODEV;
- }
- if (request_irq(SCI_RXI_IRQ, sci_rx_interrupt, SA_INTERRUPT,
- "serial", port)) {
- printk(KERN_ERR "sci: Cannot allocate rx irq.\n");
- return -ENODEV;
- }
- if (request_irq(SCI_TXI_IRQ, sci_tx_interrupt, SA_INTERRUPT,
- "serial", port)) {
- printk(KERN_ERR "sci: Cannot allocate tx irq.\n");
- return -ENODEV;
+ void (*handlers[3])(int irq, void *ptr, struct pt_regs *regs) = {
+ sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt
+ };
+
+ for (port = &sci_ports[0]; port < &sci_ports[SCI_NPORTS]; port++) {
+ for (i=0; i<3; i++) {
+ set_ipr_data(port->irqs[i], port->intc_addr, port->intc_pos, SCI_PRIORITY);
+
+ if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
+ "serial", port)) {
+ printk(KERN_ERR "sci: Cannot allocate irq.\n");
+ return -ENODEV;
+ }
+ }
}
/* XXX: How about BRI interrupt?? */
@@ -802,121 +861,21 @@ void cleanup_module(void)
* ------------------------------------------------------------
*/
-static inline void put_char(char c)
-{
- unsigned long flags;
- unsigned short status;
-
- save_and_cli(flags);
-
- do
- status = ctrl_in(SC_SR);
- while (!(status & SCI_TD_E));
-
- ctrl_outb(c, SC_TDR);
- ctrl_in(SC_SR); /* Dummy read */
- ctrl_out(SCI_TD_E_CLEAR, SC_SR);
-
- restore_flags(flags);
-}
-
#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
-static int in_gdb = 1;
-static inline void handle_error(void)
-{ /* Clear error flags */
- ctrl_out(SCI_ERROR_CLEAR, SC_SR);
-}
-
-static inline int get_char(void)
-{
- unsigned long flags;
- unsigned short status;
- int c;
-
- save_and_cli(flags);
- do {
- status = ctrl_in(SC_SR);
- if (status & SCI_ERRORS) {
- handle_error();
- continue;
- }
- } while (!(status & SCI_RD_F));
- c = ctrl_inb(SC_RDR);
- ctrl_in(SC_SR); /* Dummy read */
- ctrl_out(SCI_RDRF_CLEAR, SC_SR);
- restore_flags(flags);
-
- return c;
-}
-
-/* Taken from sh-stub.c of GDB 4.18 */
-static const char hexchars[] = "0123456789abcdef";
-static char highhex(int x)
-{
- return hexchars[(x >> 4) & 0xf];
-}
-
-static char lowhex(int x)
-{
- return hexchars[x & 0xf];
-}
-
-static void gdb_detach(void)
+static void __init gdb_detach(void)
{
asm volatile("trapa #0xff");
if (in_gdb == 1) {
in_gdb = 0;
- get_char();
- put_char('\r');
- put_char('\n');
+ get_char(sercons_port);
+ put_char(sercons_port, '\r');
+ put_char(sercons_port, '\n');
}
}
#endif
-/* send the packet in buffer. The host get's one chance to read it.
- This routine does not wait for a positive acknowledge. */
-
-static void
-put_string(const char *buffer, int count)
-{
- int i;
- const unsigned char *p = buffer;
-#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
- int checksum;
-
-if (in_gdb) {
- /* $<packet info>#<checksum>. */
- do {
- unsigned char c;
- put_char('$');
- put_char('O'); /* 'O'utput to console */
- checksum = 'O';
-
- for (i=0; i<count; i++) { /* Don't use run length encoding */
- int h, l;
-
- c = *p++;
- h = highhex(c);
- l = lowhex(c);
- put_char(h);
- put_char(l);
- checksum += h + l;
- }
- put_char('#');
- put_char(highhex(checksum));
- put_char(lowhex(checksum));
- } while (get_char() != '+');
-} else
-#endif
- for (i=0; i<count; i++) {
- if (*p == 10)
- put_char('\r');
- put_char(*p++);
- }
-}
-
/*
* Print a string to the serial port trying not to disturb
* any possible real use of the port...
@@ -924,7 +883,7 @@ if (in_gdb) {
static void serial_console_write(struct console *co, const char *s,
unsigned count)
{
- put_string(s, count);
+ put_string(sercons_port, s, count);
}
/*
@@ -938,7 +897,7 @@ static int serial_console_wait_key(struct console *co)
static kdev_t serial_console_device(struct console *c)
{
- return MKDEV(TTY_MAJOR, SCI_MINOR_START + c->index);
+ return MKDEV(SCI_MAJOR, SCI_MINOR_START + c->index);
}
/*
@@ -949,12 +908,14 @@ static kdev_t serial_console_device(struct console *c)
*/
static int __init serial_console_setup(struct console *co, char *options)
{
- int baud = 115200;
+ int baud = 9600;
int bits = 8;
int parity = 'n';
int cflag = CREAD | HUPCL | CLOCAL;
char *s;
+ sercons_port = &sci_ports[co->index];
+
if (options) {
baud = simple_strtoul(options, NULL, 10);
s = options;
@@ -983,6 +944,7 @@ static int __init serial_console_setup(struct console *co, char *options)
case 9600:
default:
cflag |= B9600;
+ baud = 9600;
break;
}
switch (bits) {
@@ -1002,14 +964,18 @@ static int __init serial_console_setup(struct console *co, char *options)
cflag |= PARENB;
break;
}
+
co->cflag = cflag;
+ sercons_baud = baud;
+
+ sci_set_termios_cflag(sercons_port, cflag, baud);
+ sercons_port->old_cflag = cflag;
- /* XXX: set baud, char, and parity here. */
return 0;
}
static struct console sercons = {
- "ttyS",
+ "ttySC",
serial_console_write,
NULL,
serial_console_device,
diff --git a/drivers/char/sh-sci.h b/drivers/char/sh-sci.h
index f501951ec..ddf5712a5 100644
--- a/drivers/char/sh-sci.h
+++ b/drivers/char/sh-sci.h
@@ -5,148 +5,135 @@
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
* Copyright (C) 1999, 2000 Niibe Yutaka
* Copyright (C) 2000 Greg Banks
+ * Modified to support multiple serial ports. Stuart Menefy (May 2000).
*
*/
#include <linux/config.h>
-#if defined(CONFIG_SH_SCI_SERIAL)
-#if defined(__sh3__)
-#define SCSMR (volatile unsigned char *)0xfffffe80
-#define SCBRR 0xfffffe82
-#define SCSCR (volatile unsigned char *)0xfffffe84
-#define SC_TDR 0xfffffe86
-#define SC_SR (volatile unsigned char *)0xfffffe88
-#define SC_RDR 0xfffffe8a
-#define SCSPTR 0xffffff7c
-#elif defined(__SH4__)
-#define SCSMR (volatile unsigned char *)0xffe00000
-#define SCBRR 0xffe00004
-#define SCSCR (volatile unsigned char *)0xffe00008
-#define SC_TDR 0xffe0000c
-#define SC_SR (volatile unsigned char *)0xffe00010
-#define SC_RDR 0xffe00014
-#define SCSPTR 0xffe0001c
+/* Values for sci_port->type */
+#define PORT_SCI 0
+#define PORT_SCIF 1
+
+/* Offsets into the sci_port->irqs array */
+#define SCIx_ERI_IRQ 0
+#define SCIx_RXI_IRQ 1
+#define SCIx_TXI_IRQ 2
+
+/* ERI, RXI, TXI, INTC reg, INTC pos */
+#define SCI_IRQS { 23, 24, 25 }, INTC_IPRB, 1
+#define SH3_SCIF_IRQS { 56, 57, 59 }, INTC_IPRE, 1
+#define SH4_SCIF_IRQS { 40, 41, 43 }, INTC_IPRC, 1
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7708)
+# define SCI_NPORTS 1
+# define SCI_INIT { \
+ { {}, PORT_SCI, 0xfffffe80, SCI_IRQS, sci_init_pins_sci } \
+}
+# define SCSPTR 0xffffff7c /* 8 bit */
+# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCI_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
+# define SCI_NPORTS 2
+# define SCI_INIT { \
+ { {}, PORT_SCI, 0xfffffe80, SCI_IRQS, sci_init_pins_sci }, \
+ { {}, PORT_SCIF, 0xA4000150, SH3_SCIF_IRQS, sci_init_pins_scif } \
+}
+# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */
+# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */
+# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCI_AND_SCIF
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+# define SCI_NPORTS 2
+# define SCI_INIT { \
+ { {}, PORT_SCI, 0xffe00000, SCI_IRQS, sci_init_pins_sci }, \
+ { {}, PORT_SCIF, 0xFFE80000, SH4_SCIF_IRQS, sci_init_pins_scif } \
+}
+# define SCSPTR1 0xffe0001c /* 8 bit SCI */
+# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
+# define SCLSR2 0xFFE80024 /* 16 bit SCIF */
+# define SCSCR_INIT(port) (((port)->type == PORT_SCI) ? \
+ 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ : \
+ 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ )
+# define SCI_AND_SCIF
+#else
+# error CPU subtype not defined
#endif
-#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+/* SCSCR */
+#define SCI_CTRL_FLAGS_TIE 0x80 /* all */
+#define SCI_CTRL_FLAGS_RIE 0x40 /* all */
+#define SCI_CTRL_FLAGS_TE 0x20 /* all */
+#define SCI_CTRL_FLAGS_RE 0x10 /* all */
+/* SCI_CTRL_FLAGS_REIE 0x08 * 7750 SCIF */
+/* SCI_CTRL_FLAGS_MPIE 0x08 * 7708 SCI, 7709 SCI, 7750 SCI */
+/* SCI_CTRL_FLAGS_TEIE 0x04 * 7708 SCI, 7709 SCI, 7750 SCI */
+/* SCI_CTRL_FLAGS_CKE1 0x02 * all */
+/* SCI_CTRL_FLAGS_CKE0 0x01 * 7708 SCI, 7709 SCI/SCIF, 7750 SCI */
-#define SCI_TD_E 0x80
-#define SCI_RD_F 0x40
-#define SCI_ORER 0x20
-#define SCI_FER 0x10
-#define SCI_PER 0x08
-#define SCI_TEND 0x04
+/* SCxSR SCI */
+#define SCI_TDRE 0x80 /* 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_RDRF 0x40 /* 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_ORER 0x20 /* 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_FER 0x10 /* 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_PER 0x08 /* 7708 SCI, 7709 SCI, 7750 SCI */
+#define SCI_TEND 0x04 /* 7708 SCI, 7709 SCI, 7750 SCI */
+/* SCI_MPB 0x02 * 7708 SCI, 7709 SCI, 7750 SCI */
+/* SCI_MPBT 0x01 * 7708 SCI, 7709 SCI, 7750 SCI */
#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ORER)
-#define SCI_TD_E_CLEAR 0x78
-#define SCI_RDRF_CLEAR 0xbc
-#define SCI_ERROR_CLEAR 0xc4
-
-#define SCI_CTRL_FLAGS_TIE 0x80
-#define SCI_CTRL_FLAGS_RIE 0x40
-#define SCI_CTRL_FLAGS_TE 0x20
-#define SCI_CTRL_FLAGS_RE 0x10
-/* TEIE=0x04 */
-#define SCI_CTRL_FLAGS_CKE1 0x02
-#define SCI_CTRL_FLAGS_CKE0 0x01
-
-#define SCI_ERI_IRQ 23
-#define SCI_RXI_IRQ 24
-#define SCI_TXI_IRQ 25
-#define SCI_TEI_IRQ 26
-#define SCI_IRQ_END 27
-
-#define SCI_IPR_ADDR INTC_IPRB
-#define SCI_IPR_POS 1
-#endif
-
-#if defined(CONFIG_SH_SCIF_SERIAL)
-#if defined(__sh3__)
-#define SCSMR (volatile unsigned char *)0xA4000150
-#define SCBRR 0xA4000152
-#define SCSCR (volatile unsigned char *)0xA4000154
-#define SC_TDR 0xA4000156
-#define SC_SR (volatile unsigned short *)0xA4000158
-#define SC_RDR 0xA400015A
-#define SCFCR (volatile unsigned char *)0xA400015C
-#define SCFDR 0xA400015E
-
-#undef SCSPTR /* SH7709 doesn't have SCSPTR */
-#define SCPCR 0xA4000116 /* Instead, it has SCPCR and SCPDR */
-#define SCPDR 0xA4000136
-#undef SCLSR
-
-#define SCSCR_INIT 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
- /* 0x33 when external clock is used */
-#define SCI_IPR_ADDR INTC_IPRE
-#define SCI_IPR_POS 1
-
-#elif defined(__SH4__)
-#define SCSMR (volatile unsigned short *)0xFFE80000
-#define SCBRR 0xFFE80004
-#define SCSCR (volatile unsigned short *)0xFFE80008
-#define SC_TDR 0xFFE8000C
-#define SC_SR (volatile unsigned short *)0xFFE80010
-#define SC_RDR 0xFFE80014
-#define SCFCR (volatile unsigned short *)0xFFE80018
-#define SCFDR 0xFFE8001C
-#define SCSPTR 0xFFE80020
-#define SCLSR 0xFFE80024
-
-#define SCSCR_INIT 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
-#define SCI_IPR_ADDR INTC_IPRC
-#define SCI_IPR_POS 1
-#endif
+/* SCxSR SCIF */
+#define SCIF_ER 0x0080 /* 7709 SCIF, 7750 SCIF */
+#define SCIF_TEND 0x0040 /* 7709 SCIF, 7750 SCIF */
+#define SCIF_TDFE 0x0020 /* 7709 SCIF, 7750 SCIF */
+#define SCIF_BRK 0x0010 /* 7709 SCIF, 7750 SCIF */
+#define SCIF_FER 0x0008 /* 7709 SCIF, 7750 SCIF */
+#define SCIF_PER 0x0004 /* 7709 SCIF, 7750 SCIF */
+#define SCIF_RDF 0x0002 /* 7709 SCIF, 7750 SCIF */
+#define SCIF_DR 0x0001 /* 7709 SCIF, 7750 SCIF */
-#define SCI_ER 0x0080
-#define SCI_TEND 0x0040
-#define SCI_TD_E 0x0020
-#define SCI_BRK 0x0010
-#define SCI_FER 0x0008
-#define SCI_PER 0x0004
-#define SCI_RD_F 0x0002
-#define SCI_DR 0x0001
-
-#define SCI_ERRORS ( SCI_PER | SCI_FER | SCI_ER | SCI_BRK)
-#define SCI_TD_E_CLEAR 0x00df
-#define SCI_TEND_CLEAR 0x00bf
-#define SCI_RDRF_CLEAR 0x00fc
-#define SCI_ERROR_CLEAR 0x0063
-
-#define SCI_CTRL_FLAGS_TIE 0x80
-#define SCI_CTRL_FLAGS_RIE 0x40
-#define SCI_CTRL_FLAGS_TE 0x20
-#define SCI_CTRL_FLAGS_RE 0x10
-#define SCI_CTRL_FLAGS_REIE 0x08
-#define SCI_CTRL_FLAGS_CKE1 0x02
-
-#if defined(__sh3__)
-#define SCI_ERI_IRQ 56
-#define SCI_RXI_IRQ 57
-#define SCI_BRI_IRQ 58
-#define SCI_TXI_IRQ 59
-#define SCI_IRQ_END 60
-#elif defined(__SH4__)
-#define SCI_ERI_IRQ 40
-#define SCI_RXI_IRQ 41
-#define SCI_BRI_IRQ 42
-#define SCI_TXI_IRQ 43
-#define SCI_IRQ_END 44
-#endif
-#endif
-
-#if defined(__sh3__)
-#define RFCR 0xffffff74
-#elif defined(__SH4__)
-#define RFCR 0xFF800028
+#define SCIF_ERRORS ( SCIF_PER | SCIF_FER | SCIF_ER | SCIF_BRK)
+
+#if defined(SCI_ONLY)
+# define SCxSR_TEND(port) SCI_TEND
+# define SCxSR_ERRORS(port) SCI_ERRORS
+# define SCxSR_RDxF(port) SCI_RDRF
+# define SCxSR_TDxE(port) SCI_TDRE
+# define SCxSR_RDxF_CLEAR(port) 0xbc
+# define SCxSR_ERROR_CLEAR(port) 0xc4
+# define SCxSR_TDxE_CLEAR(port) 0x78
+#elif defined(SCIF_ONLY)
+# define SCxSR_TEND(port) SCIF_TEND
+# define SCxSR_ERRORS(port) SCIF_ERRORS
+# define SCxSR_RDxF(port) SCIF_RDF
+# define SCxSR_TDxE(port) SCIF_TDFE
+# define SCxSR_RDxF_CLEAR(port) 0x00fc
+# define SCxSR_ERROR_CLEAR(port) 0x0063
+# define SCxSR_TDxE_CLEAR(port) 0x00df
+#else
+# define SCxSR_TEND(port) (((port)->type == PORT_SCI) ? SCI_TEND : SCIF_TEND)
+# define SCxSR_ERRORS(port) (((port)->type == PORT_SCI) ? SCI_ERRORS : SCIF_ERRORS)
+# define SCxSR_RDxF(port) (((port)->type == PORT_SCI) ? SCI_RDRF : SCIF_RDF)
+# define SCxSR_TDxE(port) (((port)->type == PORT_SCI) ? SCI_TDRE : SCIF_TDFE)
+# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
+# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0063)
+# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
#endif
+/* SCFCR */
+#define SCFCR_RFRST 0x0002
+#define SCFCR_TFRST 0x0004
+#define SCFCR_MCE 0x0008
+
#define SCI_PRIORITY 3
-#define SCI_MINOR_START 64
+#define SCI_MAJOR 204
+#define SCI_MINOR_START 8
+
+/* Generic serial flags */
#define SCI_RX_THROTTLE 0x0000001
+/* generic serial tty */
#define O_OTHER(tty) \
((O_OLCUC(tty)) ||\
(O_ONLCR(tty)) ||\
@@ -173,10 +160,85 @@
struct sci_port {
struct gs_port gs;
+ int type;
+ unsigned int base;
+ unsigned char irqs[3]; /* ERI, RXI, TXI */
+ unsigned int intc_addr, intc_pos;
+ void (*init_pins)(struct sci_port* port, unsigned int cflag);
unsigned int old_cflag;
};
-#define WAIT_RFCR_COUNTER 200
+#define SCI_IN(size, offset) \
+ unsigned int addr = port->base + (offset); \
+ if ((size) == 8) { \
+ return ctrl_inb(addr); \
+ } else { \
+ return ctrl_inw(addr); \
+ }
+#define SCI_OUT(size, offset, value) \
+ unsigned int addr = port->base + (offset); \
+ if ((size) == 8) { \
+ ctrl_outb(value, addr); \
+ } else { \
+ ctrl_outw(value, addr); \
+ }
+
+#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
+ static inline unsigned int sci_##name##_in(struct sci_port* port) \
+ { \
+ if (port->type == PORT_SCI) { \
+ SCI_IN(sci_size, sci_offset) \
+ } else { \
+ SCI_IN(scif_size, scif_offset); \
+ } \
+ } \
+ static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \
+ { \
+ if (port->type == PORT_SCI) { \
+ SCI_OUT(sci_size, sci_offset, value) \
+ } else { \
+ SCI_OUT(scif_size, scif_offset, value); \
+ } \
+ }
+
+#define CPU_SCIF_FNS(name, scif_offset, scif_size) \
+ static inline unsigned int sci_##name##_in(struct sci_port* port) \
+ { \
+ SCI_IN(scif_size, scif_offset); \
+ } \
+ static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \
+ { \
+ SCI_OUT(scif_size, scif_offset, value); \
+ }
+
+#ifdef __sh3__
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+ sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+ CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+ CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
+#else
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+ sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+ CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+ CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
+#endif
+
+/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 */
+/* name off sz off sz off sz off sz */
+SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16)
+SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8)
+SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16)
+SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8)
+SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16)
+SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8)
+SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16)
+SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16)
+
+#define sci_in(port, reg) sci_##reg##_in(port)
+#define sci_out(port, reg, value) sci_##reg##_out(port, value)
+
/*
* Values for the BitRate Register (SCBRR)
@@ -191,22 +253,17 @@ struct sci_port {
* the SCSMR register would also need to be set to non-zero values.
*
* -- Greg Banks 27Feb2000
+ *
+ * Answer: The SCBRR register is only eight bits, and the value in
+ * it gets larger with lower baud rates. At around 2400 (depending on
+ * the peripherial module clock) you run out of bits. However the
+ * lower two bits of SCSMR allow the module clock to be divided down,
+ * scaling the value which is needed in SCBRR.
+ *
+ * -- Stuart Menefy - 23 May 2000
*/
-/*
- * XXX: Well, this is not relevant...
- * Should we have config option for peripheral clock?
- * Or we get the value from time.c.
- */
-#if defined(__sh3__)
-#if defined(CONFIG_CPU_SUBTYPE_SH7709)
-#define PCLK 33333333
-#else
-#define PCLK 14745600 /* Isn't it 15MHz? */
-#endif
-#elif defined(__SH4__)
-#define PCLK 33333333
-#endif
+#define PCLK (current_cpu_data.module_clock)
#define SCBRR_VALUE(bps) (PCLK/(32*bps)-1)
#define BPS_2400 SCBRR_VALUE(2400)
@@ -215,3 +272,107 @@ struct sci_port {
#define BPS_19200 SCBRR_VALUE(19200)
#define BPS_38400 SCBRR_VALUE(38400)
#define BPS_115200 SCBRR_VALUE(115200)
+
+#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
+/* Taken from sh-stub.c of GDB 4.18 */
+static const char hexchars[] = "0123456789abcdef";
+
+static __inline__ char highhex(int x)
+{
+ return hexchars[(x >> 4) & 0xf];
+}
+
+static __inline__ char lowhex(int x)
+{
+ return hexchars[x & 0xf];
+}
+#endif
+
+static __inline__ void put_char(struct sci_port *port, char c)
+{
+ unsigned long flags;
+ unsigned short status;
+
+ save_and_cli(flags);
+
+ do
+ status = sci_in(port, SCxSR);
+ while (!(status & SCxSR_TDxE(port)));
+
+ sci_out(port, SCxTDR, c);
+ sci_in(port, SCxSR); /* Dummy read */
+ sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
+
+ restore_flags(flags);
+}
+
+static __inline__ void handle_error(struct sci_port *port)
+{ /* Clear error flags */
+ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+}
+
+static __inline__ int get_char(struct sci_port *port)
+{
+ unsigned long flags;
+ unsigned short status;
+ int c;
+
+ save_and_cli(flags);
+ do {
+ status = sci_in(port, SCxSR);
+ if (status & SCxSR_ERRORS(port)) {
+ handle_error(port);
+ continue;
+ }
+ } while (!(status & SCxSR_RDxF(port)));
+ c = sci_in(port, SCxRDR);
+ sci_in(port, SCxSR); /* Dummy read */
+ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+ restore_flags(flags);
+
+ return c;
+}
+
+/*
+ * Send the packet in buffer. The host get's one chance to read it.
+ * This routine does not wait for a positive acknowledge.
+ */
+
+static __inline__ void put_string(struct sci_port *port,
+ const char *buffer, int count)
+{
+ int i;
+ const unsigned char *p = buffer;
+#ifdef CONFIG_DEBUG_KERNEL_WITH_GDB_STUB
+ int checksum;
+
+if (IN_GDB) {
+ /* $<packet info>#<checksum>. */
+ do {
+ unsigned char c;
+ put_char(port, '$');
+ put_char(port, 'O'); /* 'O'utput to console */
+ checksum = 'O';
+
+ for (i=0; i<count; i++) { /* Don't use run length encoding */
+ int h, l;
+
+ c = *p++;
+ h = highhex(c);
+ l = lowhex(c);
+ put_char(port, h);
+ put_char(port, l);
+ checksum += h + l;
+ }
+ put_char(port, '#');
+ put_char(port, highhex(checksum));
+ put_char(port, lowhex(checksum));
+ } while (get_char(port) != '+');
+} else
+#endif
+ for (i=0; i<count; i++) {
+ if (*p == 10)
+ put_char(port, '\r');
+ put_char(port, *p++);
+ }
+}
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 1898849d8..fdaeeaea0 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -511,8 +511,6 @@ static void stl_breakctl(struct tty_struct *tty, int state);
static void stl_waituntilsent(struct tty_struct *tty, int timeout);
static void stl_sendxchar(struct tty_struct *tty, char ch);
static void stl_hangup(struct tty_struct *tty);
-static int stl_memopen(struct inode *ip, struct file *fp);
-static int stl_memclose(struct inode *ip, struct file *fp);
static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
static int stl_portinfo(stlport_t *portp, int portnr, char *pos);
static int stl_readproc(char *page, char **start, off_t off, int count, int *eof, void *data);
@@ -744,9 +742,8 @@ static unsigned int sc26198_baudtable[] = {
* to get at port stats - only not using the port device itself.
*/
static struct file_operations stl_fsiomem = {
+ owner: THIS_MODULE,
ioctl: stl_memioctl,
- open: stl_memopen,
- release: stl_memclose,
};
/*****************************************************************************/
@@ -2795,8 +2792,8 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
*/
#if DEBUG
printk("%s(%d): BAR[]=%x,%x,%x,%x IRQ=%x\n", __FILE__, __LINE__,
- devp->resource[0].start, devp->resource[1].start,
- devp->resource[2].start, devp->resource[3].start, devp->irq);
+ pci_resource_start(devp, 0), pci_resource_start(devp, 1),
+ pci_resource_start(devp, 2), pci_resource_start(devp, 3), devp->irq);
#endif
/*
@@ -2805,22 +2802,16 @@ static inline int stl_initpcibrd(int brdtype, struct pci_dev *devp)
*/
switch (brdtype) {
case BRD_ECHPCI:
- brdp->ioaddr2 = (devp->resource[0].start &
- PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr1 = (devp->resource[1].start &
- PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr2 = pci_resource_start(devp, 0);
+ brdp->ioaddr1 = pci_resource_start(devp, 1);
break;
case BRD_ECH64PCI:
- brdp->ioaddr2 = (devp->resource[2].start &
- PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr1 = (devp->resource[1].start &
- PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr2 = pci_resource_start(devp, 2);
+ brdp->ioaddr1 = pci_resource_start(devp, 1);
break;
case BRD_EASYIOPCI:
- brdp->ioaddr1 = (devp->resource[2].start &
- PCI_BASE_ADDRESS_IO_MASK);
- brdp->ioaddr2 = (devp->resource[1].start &
- PCI_BASE_ADDRESS_IO_MASK);
+ brdp->ioaddr1 = pci_resource_start(devp, 2);
+ brdp->ioaddr2 = pci_resource_start(devp, 1);
break;
default:
printk("STALLION: unknown PCI board type=%d\n", brdtype);
@@ -3123,27 +3114,6 @@ static int stl_getbrdstruct(unsigned long arg)
/*****************************************************************************/
/*
- * Memory device open code. Need to keep track of opens and close
- * for module handling.
- */
-
-static int stl_memopen(struct inode *ip, struct file *fp)
-{
- MOD_INC_USE_COUNT;
- return(0);
-}
-
-/*****************************************************************************/
-
-static int stl_memclose(struct inode *ip, struct file *fp)
-{
- MOD_DEC_USE_COUNT;
- return(0);
-}
-
-/*****************************************************************************/
-
-/*
* The "staliomem" device is also required to do some special operations
* on the board and/or ports. In this driver it is mostly used for stats
* collection.
diff --git a/drivers/char/stradis.c b/drivers/char/stradis.c
index f157d4e52..949aa9532 100644
--- a/drivers/char/stradis.c
+++ b/drivers/char/stradis.c
@@ -2055,10 +2055,13 @@ static int configure_saa7146(struct pci_dev *dev, int num)
saa->id = dev->device;
saa->irq = dev->irq;
saa->video_dev.minor = -1;
- saa->saa7146_adr = dev->resource[0].start;
+ saa->saa7146_adr = pci_resource_start(dev, 0);
pci_read_config_byte(dev, PCI_CLASS_REVISION, &saa->revision);
- saa->saa7146_mem = ioremap(((saa->saa7146_adr) &
- PCI_BASE_ADDRESS_MEM_MASK), 0x200);
+
+ saa->saa7146_mem = ioremap(saa->saa7146_adr, 0x200);
+ if (!saa->saa7146_mem)
+ return -EIO;
+
memcpy(&(saa->i2c), &saa7146_i2c_bus_template, sizeof(struct i2c_bus));
memcpy(&saa->video_dev, &saa_template, sizeof(saa_template));
sprintf(saa->i2c.name, "stradis%d", num);
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 15a24851f..82e3cae1e 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -304,8 +304,6 @@ static int sx_init_board (struct sx_board *board);
static int sx_init_portstructs (int nboards, int nports);
static int sx_fw_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-static int sx_fw_open(struct inode *inode, struct file *filp);
-static INT sx_fw_release(struct inode *inode, struct file *filp);
static int sx_init_drivers(void);
@@ -419,9 +417,8 @@ static struct real_driver sx_real_driver = {
*/
static struct file_operations sx_fw_fops = {
+ owner: THIS_MODULE,
ioctl: sx_fw_ioctl,
- open: sx_fw_open,
- release: sx_fw_release,
};
struct miscdevice sx_fw_device = {
@@ -1418,25 +1415,6 @@ static void sx_shutdown_port (void * ptr)
* interface with the rest of the system *
* ********************************************************************** */
-
-static int sx_fw_open(struct inode *inode, struct file *filp)
-{
- func_enter ();
- MOD_INC_USE_COUNT;
- func_exit ();
- return 0;
-}
-
-
-static INT sx_fw_release(struct inode *inode, struct file *filp)
-{
- func_enter ();
- MOD_DEC_USE_COUNT;
- func_exit ();
- return NO_ERROR;
-}
-
-
static int sx_open (struct tty_struct * tty, struct file * filp)
{
struct sx_port *port;
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index d29c63407..133f19aac 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -2177,10 +2177,6 @@ static int qic02_tape_open(struct inode * inode, struct file * filp)
int open_error;
open_error = qic02_tape_open_no_use_count(inode, filp);
- if (!open_error)
- {
- MOD_INC_USE_COUNT;
- }
return open_error;
}
@@ -2440,9 +2436,6 @@ static int qic02_tape_release(struct inode * inode, struct file * filp)
(void) do_qic_cmd(QCMD_REWIND, TIM_R);
}
}
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
return 0;
} /* qic02_tape_release */
@@ -2766,6 +2759,7 @@ static int qic02_tape_ioctl(struct inode * inode, struct file * filp,
/* These are (most) of the interface functions: */
static struct file_operations qic02_tape_fops = {
+ owner: THIS_MODULE,
llseek: qic02_tape_lseek, /* not allowed */
read: qic02_tape_read,
write: qic02_tape_write,
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 1516d985e..8a03fed26 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1430,49 +1430,6 @@ static unsigned int tty_poll(struct file * filp, poll_table * wait)
return 0;
}
-/*
- * fasync_helper() is used by some character device drivers (mainly mice)
- * to set up the fasync queue. It returns negative on error, 0 if it did
- * no changes and positive if it added/deleted the entry.
- */
-int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
-{
- struct fasync_struct *fa, **fp;
- unsigned long flags;
-
- for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) {
- if (fa->fa_file == filp)
- break;
- }
-
- if (on) {
- if (fa) {
- fa->fa_fd = fd;
- return 0;
- }
- fa = (struct fasync_struct *)kmalloc(sizeof(struct fasync_struct), GFP_KERNEL);
- if (!fa)
- return -ENOMEM;
- fa->magic = FASYNC_MAGIC;
- fa->fa_file = filp;
- fa->fa_fd = fd;
- save_flags(flags);
- cli();
- fa->fa_next = *fapp;
- *fapp = fa;
- restore_flags(flags);
- return 1;
- }
- if (!fa)
- return 0;
- save_flags(flags);
- cli();
- *fp = fa->fa_next;
- restore_flags(flags);
- kfree(fa);
- return 1;
-}
-
static int tty_fasync(int fd, struct file * filp, int on)
{
struct tty_struct * tty;
diff --git a/drivers/char/tuner.c b/drivers/char/tuner.c
index 0ed55b715..81e19a4ab 100644
--- a/drivers/char/tuner.c
+++ b/drivers/char/tuner.c
@@ -10,6 +10,7 @@
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/videodev.h>
+#include <linux/init.h>
#include "tuner.h"
#include "audiochip.h"
@@ -428,22 +429,19 @@ static struct i2c_client client_template =
EXPORT_NO_SYMBOLS;
-#ifdef MODULE
-int init_module(void)
-#else
-int i2c_tuner_init(void)
-#endif
+int tuner_init_module(void)
{
i2c_add_driver(&driver);
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+void tuner_cleanup_module(void)
{
i2c_del_driver(&driver);
}
-#endif
+
+module_init(tuner_init_module);
+module_exit(tuner_cleanup_module);
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/char/tvmixer.c b/drivers/char/tvmixer.c
new file mode 100644
index 000000000..0ef5bbd03
--- /dev/null
+++ b/drivers/char/tvmixer.c
@@ -0,0 +1,351 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <asm/semaphore.h>
+#include <linux/init.h>
+
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <asm/uaccess.h>
+
+#include "audiochip.h"
+
+#define DEV_MAX 4
+
+static int debug = 0;
+static int devnr = -1;
+
+MODULE_PARM(debug,"i");
+MODULE_PARM(devnr,"i");
+
+/* ----------------------------------------------------------------------- */
+
+struct TVMIXER {
+ struct i2c_client *dev;
+ int minor;
+ int count;
+};
+
+static struct TVMIXER devices[DEV_MAX];
+
+static int tvmixer_adapters(struct i2c_adapter *adap);
+static int tvmixer_clients(struct i2c_client *client);
+
+static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int tvmixer_open(struct inode *inode, struct file *file);
+static int tvmixer_release(struct inode *inode, struct file *file);
+static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin);
+
+
+static struct i2c_driver driver = {
+ "tv card mixer driver",
+ 42 /* I2C_DRIVERID_FIXME */,
+ I2C_DF_DUMMY,
+ tvmixer_adapters,
+ tvmixer_clients,
+};
+
+static struct file_operations tvmixer_fops = {
+ owner: THIS_MODULE,
+ llseek: tvmixer_llseek,
+ ioctl: tvmixer_ioctl,
+ open: tvmixer_open,
+ release: tvmixer_release,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int mix_to_v4l(int i)
+{
+ int r;
+
+ r = ((i & 0xff) * 65536 + 50) / 100;
+ if (r > 65535) r = 65535;
+ if (r < 0) r = 0;
+ return r;
+}
+
+static int v4l_to_mix(int i)
+{
+ int r;
+
+ r = (i * 100 + 32768) / 65536;
+ if (r > 100) r = 100;
+ if (r < 0) r = 0;
+ return r | (r << 8);
+}
+
+static int v4l_to_mix2(int l, int r)
+{
+ r = (r * 100 + 32768) / 65536;
+ if (r > 100) r = 100;
+ if (r < 0) r = 0;
+ l = (l * 100 + 32768) / 65536;
+ if (l > 100) l = 100;
+ if (l < 0) l = 0;
+ return (r << 8) | l;
+}
+
+static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct video_audio va;
+ int left,right,ret,val = 0;
+ struct TVMIXER *mix = file->private_data;
+ struct i2c_client *client = mix->dev;
+
+ if (NULL == client)
+ return -ENODEV;
+
+ if (cmd == SOUND_MIXER_INFO) {
+ mixer_info info;
+ strncpy(info.id, "tv card", sizeof(info.id));
+ strncpy(info.name, client->name, sizeof(info.name));
+ info.modify_counter = 42 /* FIXME */;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == SOUND_OLD_MIXER_INFO) {
+ _old_mixer_info info;
+ strncpy(info.id, "tv card", sizeof(info.id));
+ strncpy(info.name, client->name, sizeof(info.name));
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ /* read state */
+ memset(&va,0,sizeof(va));
+ client->driver->command(client,VIDIOCGAUDIO,&va);
+
+ switch (cmd) {
+ case MIXER_READ(SOUND_MIXER_RECMASK):
+ case MIXER_READ(SOUND_MIXER_CAPS):
+ case MIXER_READ(SOUND_MIXER_RECSRC):
+ case MIXER_WRITE(SOUND_MIXER_RECSRC):
+ ret = 0;
+ break;
+
+ case MIXER_READ(SOUND_MIXER_STEREODEVS):
+ ret = SOUND_MASK_VOLUME;
+ break;
+ case MIXER_READ(SOUND_MIXER_DEVMASK):
+ ret = SOUND_MASK_VOLUME;
+ if (va.flags & VIDEO_AUDIO_BASS)
+ ret |= SOUND_MASK_BASS;
+ if (va.flags & VIDEO_AUDIO_TREBLE)
+ ret |= SOUND_MASK_TREBLE;
+ break;
+
+ case MIXER_WRITE(SOUND_MIXER_VOLUME):
+ left = mix_to_v4l(val);
+ right = mix_to_v4l(val >> 8);
+ va.volume = MAX(left,right);
+ va.balance = (32768*MIN(left,right)) / (va.volume ? va.volume : 1);
+ va.balance = (left<right) ? (65535-va.balance) : va.balance;
+ client->driver->command(client,VIDIOCSAUDIO,&va);
+ client->driver->command(client,VIDIOCGAUDIO,&va);
+ /* fall throuth */
+ case MIXER_READ(SOUND_MIXER_VOLUME):
+ left = (MIN(65536 - va.balance,32768) *
+ va.volume) / 32768;
+ right = (MIN(va.balance,32768) *
+ va.volume) / 32768;
+ ret = v4l_to_mix2(left,right);
+ break;
+
+ case MIXER_WRITE(SOUND_MIXER_BASS):
+ va.bass = mix_to_v4l(val);
+ client->driver->command(client,VIDIOCSAUDIO,&va);
+ client->driver->command(client,VIDIOCGAUDIO,&va);
+ /* fall throuth */
+ case MIXER_READ(SOUND_MIXER_BASS):
+ ret = v4l_to_mix(va.bass);
+ break;
+
+ case MIXER_WRITE(SOUND_MIXER_TREBLE):
+ va.treble = mix_to_v4l(val);
+ client->driver->command(client,VIDIOCSAUDIO,&va);
+ client->driver->command(client,VIDIOCGAUDIO,&va);
+ /* fall throuth */
+ case MIXER_READ(SOUND_MIXER_TREBLE):
+ ret = v4l_to_mix(va.treble);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if (put_user(ret, (int *)arg))
+ return -EFAULT;
+ return 0;
+}
+
+static int tvmixer_open(struct inode *inode, struct file *file)
+{
+ int i, minor = MINOR(inode->i_rdev);
+ struct TVMIXER *mix = NULL;
+ struct i2c_client *client = NULL;
+
+ for (i = 0; i < DEV_MAX; i++) {
+ if (devices[i].minor == minor) {
+ mix = devices+i;
+ client = mix->dev;
+ break;
+ }
+ }
+
+ if (NULL == client)
+ return -ENODEV;
+
+ /* lock bttv in memory while the mixer is in use */
+ file->private_data = mix;
+ if (client->adapter->inc_use)
+ client->adapter->inc_use(client->adapter);
+ return 0;
+}
+
+static int tvmixer_release(struct inode *inode, struct file *file)
+{
+ struct TVMIXER *mix = file->private_data;
+ struct i2c_client *client = mix->dev;
+
+ if (NULL == client)
+ return -ENODEV;
+
+ if (client->adapter->dec_use)
+ client->adapter->dec_use(client->adapter);
+ return 0;
+}
+
+static loff_t tvmixer_llseek(struct file *file, loff_t offset, int origin)
+{
+ return -ESPIPE;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int tvmixer_adapters(struct i2c_adapter *adap)
+{
+ return 0;
+}
+
+static int tvmixer_clients(struct i2c_client *client)
+{
+ struct video_audio va;
+ int i,minor;
+
+ /* TV card ??? */
+ if (client->adapter->id != (I2C_ALGO_BIT | I2C_HW_B_BT848)) {
+ if (debug)
+ printk("tvmixer: %s is not a tv card\n",
+ client->adapter->name);
+ return -1;
+ }
+ printk("tvmixer: debug: %s\n",client->name);
+
+ /* unregister ?? */
+ for (i = 0; i < DEV_MAX; i++) {
+ if (devices[i].dev == client) {
+ /* unregister */
+ unregister_sound_mixer(devices[i].minor);
+ devices[i].dev = NULL;
+ devices[i].minor = -1;
+ printk("tvmixer: %s unregistered (#1)\n",client->name);
+ return 0;
+ }
+ }
+
+ /* look for a free slot */
+ for (i = 0; i < DEV_MAX; i++)
+ if (NULL == devices[i].dev)
+ break;
+ if (i == DEV_MAX) {
+ printk(KERN_WARNING "tvmixer: DEV_MAX too small\n");
+ return -1;
+ }
+
+ /* audio chip with mixer ??? */
+ if (NULL == client->driver->command) {
+ if (debug)
+ printk("tvmixer: %s: driver->command is NULL\n",
+ client->driver->name);
+ return -1;
+ }
+ memset(&va,0,sizeof(va));
+ if (0 != client->driver->command(client,VIDIOCGAUDIO,&va)) {
+ if (debug)
+ printk("tvmixer: %s: VIDIOCGAUDIO failed\n",
+ client->name);
+ return -1;
+ }
+ if (0 == (va.flags & VIDEO_AUDIO_VOLUME)) {
+ if (debug)
+ printk("tvmixer: %s: has no volume control\n",
+ client->name);
+ return -1;
+ }
+
+ /* everything is fine, register */
+ if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) {
+ printk(KERN_ERR "tvmixer: cannot allocate mixer device\n");
+ return -1;
+ }
+
+ devices[i].minor = minor;
+ devices[i].count = 0;
+ devices[i].dev = client;
+ printk("tvmixer: %s (%s) registered with minor %d\n",
+ client->name,client->adapter->name,minor);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int tvmixer_init_module(void)
+{
+ int i;
+
+ for (i = 0; i < DEV_MAX; i++)
+ devices[i].minor = -1;
+ i2c_add_driver(&driver);
+ return 0;
+}
+
+void tvmixer_cleanup_module(void)
+{
+ int i;
+
+ i2c_del_driver(&driver);
+ for (i = 0; i < DEV_MAX; i++) {
+ if (devices[i].minor != -1) {
+ unregister_sound_mixer(devices[i].minor);
+ printk("tvmixer: %s unregistered (#2)\n",
+ devices[i].dev->name);
+ }
+ }
+}
+
+module_init(tvmixer_init_module);
+module_exit(tvmixer_cleanup_module);
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index 98c9e9731..ababd833f 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -51,7 +51,6 @@ struct videodev_proc_data {
char name[16];
struct video_device *vdev;
struct proc_dir_entry *proc_entry;
- struct video_capability vcap;
};
static struct proc_dir_entry *video_dev_proc_entry = NULL;
@@ -63,7 +62,7 @@ LIST_HEAD(videodev_proc_list);
#ifdef CONFIG_VIDEO_BT848
-extern int i2c_tuner_init(struct video_init *);
+extern int tuner_init_module(struct video_init *);
#endif
#ifdef CONFIG_VIDEO_BWQCAM
extern int init_bw_qcams(struct video_init *);
@@ -80,7 +79,7 @@ extern int init_zoran_cards(struct video_init *);
static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_BT848
- {"i2c-tuner", i2c_tuner_init},
+ {"i2c-tuner", tuner_init_module},
#endif
#ifdef CONFIG_VIDEO_BWQCAM
{"bw-qcam", init_bw_qcams},
@@ -287,14 +286,6 @@ static int videodev_proc_read(char *page, char **start, off_t off,
PRINT_VID_TYPE(VID_TYPE_MJPEG_ENCODER);
out += sprintf (out, "\n");
out += sprintf (out, "hardware : 0x%x\n", vfd->hardware);
-#if 0
- out += sprintf (out, "channels : %d\n", d->vcap.channels);
- out += sprintf (out, "audios : %d\n", d->vcap.audios);
- out += sprintf (out, "maxwidth : %d\n", d->vcap.maxwidth);
- out += sprintf (out, "maxheight : %d\n", d->vcap.maxheight);
- out += sprintf (out, "minwidth : %d\n", d->vcap.minwidth);
- out += sprintf (out, "minheight : %d\n", d->vcap.minheight);
-#endif
skip:
len = out - page;
@@ -360,8 +351,6 @@ static void videodev_proc_create_dev (struct video_device *vfd, char *name)
d->vdev = vfd;
strcpy (d->name, name);
- /* How can I get capability information ? */
-
list_add (&d->proc_list, &videodev_proc_list);
}
@@ -575,3 +564,4 @@ EXPORT_SYMBOL(video_unregister_device);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
+
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 831b51654..c63df1039 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -62,7 +62,7 @@ struct vt_struct *vt_cons[MAX_NR_CONSOLES];
*/
unsigned char keyboard_type = KB_101;
-#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__)
+#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__)
asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on);
#endif
@@ -472,7 +472,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ucval = keyboard_type;
goto setchar;
-#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__)
+#if !defined(__alpha__) && !defined(__mips__) && !defined(__arm__) && !defined(__sh__)
/*
* These cannot be implemented on any machine that implements
* ioperm() in user level (such as Alpha PCs).
@@ -592,6 +592,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDGETKEYCODE:
case KDSETKEYCODE:
+ if(!capable(CAP_SYS_ADMIN))
+ perm=0;
return do_kbkeycode_ioctl(cmd, (struct kbkeycode *)arg, perm);
case KDGKBENT:
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index 0ce42945d..3ac86bf3a 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -337,7 +337,6 @@ static int wdt_open(struct inode *inode, struct file *file)
case WATCHDOG_MINOR:
if(wdt_is_open)
return -EBUSY;
- MOD_INC_USE_COUNT;
/*
* Activate
*/
@@ -353,7 +352,6 @@ static int wdt_open(struct inode *inode, struct file *file)
outb_p(0, WDT_DC); /* Enable */
return 0;
case TEMP_MINOR:
- MOD_INC_USE_COUNT;
return 0;
default:
return -ENODEV;
@@ -382,7 +380,6 @@ static int wdt_release(struct inode *inode, struct file *file)
#endif
wdt_is_open=0;
}
- MOD_DEC_USE_COUNT;
return 0;
}
@@ -416,6 +413,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
static struct file_operations wdt_fops = {
+ owner: THIS_MODULE,
llseek: wdt_llseek,
read: wdt_read,
write: wdt_write,
diff --git a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c
index 6e99a72ac..2bd09930a 100644
--- a/drivers/char/wdt_pci.c
+++ b/drivers/char/wdt_pci.c
@@ -28,6 +28,7 @@
* Parameterized timeout
* JP Nollmann : Added support for PCI wdt501p
* Alan Cox : Split ISA and PCI cards into two drivers
+ * Jeff Garzik : PCI cleanups
*/
#include <linux/config.h>
@@ -53,6 +54,8 @@
#include <linux/pci.h>
+#define PFX "wdt_pci: "
+
/*
* Until Access I/O gets their application for a PCI vendor ID approved,
* I don't think that it's appropriate to move these constants into the
@@ -487,12 +490,86 @@ static struct notifier_block wdtpci_notifier=
0
};
-#ifdef MODULE
-#define wdtpci_init init_module
+static int __init wdtpci_init_one (struct pci_dev *dev,
+ const struct pci_device_id *ent)
+{
+ static int dev_count = 0;
+
+ dev_count++;
+ if (dev_count > 1) {
+ printk (KERN_ERR PFX
+ "this driver only supports 1 device\n");
+ return -ENODEV;
+ }
+
+ irq = dev->irq;
+ io = pci_resource_start (dev, 2);
+ printk ("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X "
+ "(Interrupt %d)\n", io, irq);
+
+ if (pci_enable_device (dev))
+ goto err_out;
+
+ if (request_region (io, 16, "wdt-pci") == NULL) {
+ printk (KERN_ERR PFX "I/O %d is not free.\n", io);
+ goto err_out;
+ }
+
+ if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ,
+ "wdt-pci", &wdtpci_miscdev)) {
+ printk (KERN_ERR PFX "IRQ %d is not free.\n", irq);
+ goto err_out_free_res;
+ }
+
+ misc_register (&wdtpci_miscdev);
+
+#ifdef CONFIG_WDT_501
+ misc_register (&temp_miscdev);
+#endif
+
+ register_reboot_notifier (&wdtpci_notifier);
+
+ return 0;
+
+err_out_free_res:
+ release_region (io, 16);
+err_out:
+ return -EIO;
+}
+
+
+static void __exit wdtpci_remove_one (struct pci_dev *pdev)
+{
+ /* here we assume only one device will ever have
+ * been picked up and registered by probe function */
+ unregister_reboot_notifier(&wdtpci_notifier);
+#ifdef CONFIG_WDT_501_PCI
+ misc_deregister(&temp_miscdev);
+#endif
+ misc_deregister(&wdtpci_miscdev);
+ free_irq(irq, &wdtpci_miscdev);
+ release_region(io, 16);
+}
+
+
+static struct pci_device_id wdtpci_pci_tbl[] __initdata = {
+ { PCI_VENDOR_ID_ACCESSIO, PCI_DEVICE_ID_WDG_CSM, PCI_ANY_ID, PCI_ANY_ID, },
+ { 0, }, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, wdtpci_pci_tbl);
+
+
+static struct pci_driver wdtpci_driver = {
+ name: "wdt-pci",
+ id_table: wdtpci_pci_tbl,
+ probe: wdtpci_init_one,
+ remove: wdtpci_remove_one,
+};
+
/**
- * cleanup_module:
+ * wdtpci_cleanup:
*
* Unload the watchdog. You cannot do this with any file handles open.
* If your watchdog is set to continue ticking on close and you unload
@@ -501,18 +578,11 @@ static struct notifier_block wdtpci_notifier=
* module in 60 seconds or reboot.
*/
-void cleanup_module(void)
+static void __exit wdtpci_cleanup(void)
{
- misc_deregister(&wdtpci_miscdev);
-#ifdef CONFIG_WDT_501_PCI
- misc_deregister(&temp_miscdev);
-#endif
- unregister_reboot_notifier(&wdtpci_notifier);
- release_region(io,16);
- free_irq(irq, &wdtpci_miscdev);
+ pci_unregister_driver (&wdtpci_driver);
}
-#endif
/**
* wdtpci_init:
@@ -522,37 +592,16 @@ void cleanup_module(void)
* The open() function will actually kick the board off.
*/
-int __init wdtpci_init(void)
+static int __init wdtpci_init(void)
{
- struct pci_dev *dev = NULL;
-
- if (pci_present())
- {
- while ((dev = pci_find_device(PCI_VENDOR_ID_ACCESSIO,
- PCI_DEVICE_ID_WDG_CSM, dev))) {
- /* See if we can do this device */
- irq = dev->irq;
- io = dev->resource[2].start;
- printk("WDT501-P(PCI-WDG-CSM) driver 0.07 at %X "
- "(Interrupt %d)\n", io, irq);
- }
- }
- if(request_region(io, 16, "wdt-pci")==NULL)
- {
- printk(KERN_ERR "I/O %d is not free.\n", io);
- return -EIO;
- }
- if(request_irq(irq, wdtpci_interrupt, SA_INTERRUPT|SA_SHIRQ, "wdt-pci", &wdtpci_miscdev))
- {
- printk(KERN_ERR "IRQ %d is not free.\n", irq);
- release_region(io, 16);
- return -EIO;
- }
- misc_register(&wdtpci_miscdev);
-#ifdef CONFIG_WDT_501
- misc_register(&temp_miscdev);
-#endif
- register_reboot_notifier(&wdtpci_notifier);
+ int rc = pci_register_driver (&wdtpci_driver);
+
+ if (rc < 1)
+ return -ENODEV;
+
return 0;
}
+
+module_init(wdtpci_init);
+module_exit(wdtpci_cleanup);