summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Config.in8
-rw-r--r--drivers/char/Makefile31
-rw-r--r--drivers/char/acquirewdt.c26
-rw-r--r--drivers/char/drm/agpsupport.c23
-rw-r--r--drivers/char/drm/auth.c6
-rw-r--r--drivers/char/drm/bufs.c85
-rw-r--r--drivers/char/drm/context.c36
-rw-r--r--drivers/char/drm/dma.c16
-rw-r--r--drivers/char/drm/drawable.c3
-rw-r--r--drivers/char/drm/drm.h7
-rw-r--r--drivers/char/drm/drmP.h86
-rw-r--r--drivers/char/drm/ffb_context.c38
-rw-r--r--drivers/char/drm/fops.c3
-rw-r--r--drivers/char/drm/gamma_dma.c28
-rw-r--r--drivers/char/drm/gamma_drv.c71
-rw-r--r--drivers/char/drm/i810_bufs.c70
-rw-r--r--drivers/char/drm/i810_context.c33
-rw-r--r--drivers/char/drm/i810_dma.c55
-rw-r--r--drivers/char/drm/i810_drv.c77
-rw-r--r--drivers/char/drm/ioctl.c30
-rw-r--r--drivers/char/drm/lists.c20
-rw-r--r--drivers/char/drm/lock.c11
-rw-r--r--drivers/char/drm/mga_bufs.c123
-rw-r--r--drivers/char/drm/mga_context.c42
-rw-r--r--drivers/char/drm/mga_dma.c410
-rw-r--r--drivers/char/drm/mga_drm.h27
-rw-r--r--drivers/char/drm/mga_drv.c133
-rw-r--r--drivers/char/drm/mga_drv.h163
-rw-r--r--drivers/char/drm/mga_state.c316
-rw-r--r--drivers/char/drm/r128_bufs.c30
-rw-r--r--drivers/char/drm/r128_context.c36
-rw-r--r--drivers/char/drm/r128_dma.c55
-rw-r--r--drivers/char/drm/r128_drv.c29
-rw-r--r--drivers/char/drm/r128_drv.h6
-rw-r--r--drivers/char/drm/tdfx_context.c38
-rw-r--r--drivers/char/drm/tdfx_drv.c91
-rw-r--r--drivers/char/drm/vm.c2
-rw-r--r--drivers/char/efirtc.c2
-rw-r--r--drivers/char/ftape/lowlevel/ftape-calibr.c2
-rw-r--r--drivers/char/ftape/lowlevel/ftape-ctl.c4
-rw-r--r--drivers/char/ftape/lowlevel/ftape-rw.c8
-rw-r--r--drivers/char/ftape/lowlevel/ftape-tracing.h2
-rw-r--r--drivers/char/hp600_keyb.c2
-rw-r--r--drivers/char/i810-tco.c3
-rw-r--r--drivers/char/i810_rng.c208
-rw-r--r--drivers/char/joystick/pcigame.c2
-rw-r--r--drivers/char/lp.c9
-rw-r--r--drivers/char/mem.c57
-rw-r--r--drivers/char/misc.c18
-rw-r--r--drivers/char/mixcomwd.c23
-rw-r--r--drivers/char/nvram.c25
-rw-r--r--drivers/char/nwflash.c61
-rw-r--r--drivers/char/pcmcia/serial_cb.c8
-rw-r--r--drivers/char/pcmcia/serial_cs.c64
-rw-r--r--drivers/char/pcwd.c13
-rw-r--r--drivers/char/pcxx.c75
-rw-r--r--drivers/char/ppdev.c26
-rw-r--r--drivers/char/qpmouse.c7
-rw-r--r--drivers/char/raw.c8
-rw-r--r--drivers/char/rocket.c2
-rw-r--r--drivers/char/rtc.c2
-rw-r--r--drivers/char/sbc60xxwdt.c2
-rw-r--r--drivers/char/serial.c10
-rw-r--r--drivers/char/serial_amba.c2030
-rw-r--r--drivers/char/sh-sci.c140
-rw-r--r--drivers/char/sh-sci.h61
-rw-r--r--drivers/char/softdog.c31
-rw-r--r--drivers/char/toshiba.c522
-rw-r--r--drivers/char/tty_io.c3
-rw-r--r--drivers/char/wdt.c75
-rw-r--r--drivers/char/wdt285.c5
-rw-r--r--drivers/char/wdt977.c1
-rw-r--r--drivers/char/wdt_pci.c48
73 files changed, 4361 insertions, 1462 deletions
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 7872a6f00..1ec7792a6 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -16,7 +16,7 @@ if [ "$CONFIG_SERIAL" = "y" ]; then
tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL
fi
fi
-bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED
+dep_bool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL
if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then
bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS
bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ
@@ -90,8 +90,8 @@ if [ "$CONFIG_BUSMOUSE" != "n" ]; then
dep_tristate ' ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE $CONFIG_BUSMOUSE
dep_tristate ' Logitech busmouse support' CONFIG_LOGIBUSMOUSE $CONFIG_BUSMOUSE
dep_tristate ' Microsoft busmouse support' CONFIG_MS_BUSMOUSE $CONFIG_BUSMOUSE
- if [ "$CONFIG_ADB" = "y" ]; then
- dep_tristate ' Apple Desktop Bus mouse support' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
+ if [ "$CONFIG_ADB" = "y" -a "$CONFIG_ADB_KEYBOARD" = "y" ]; then
+ dep_tristate ' Apple Desktop Bus mouse support (old driver)' CONFIG_ADBMOUSE $CONFIG_BUSMOUSE
fi
fi
@@ -122,6 +122,7 @@ comment 'Watchdog Cards'
bool 'Watchdog Timer Support' CONFIG_WATCHDOG
if [ "$CONFIG_WATCHDOG" != "n" ]; then
bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
+ tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG
tristate ' WDT Watchdog timer' CONFIG_WDT
tristate ' WDT PCI Watchdog timer' CONFIG_WDTPCI
if [ "$CONFIG_WDT" != "n" ]; then
@@ -130,7 +131,6 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
bool ' Fan Tachometer' CONFIG_WDT_501_FAN
fi
fi
- 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
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index b7a71c0f5..1136cc0f4 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -101,6 +101,8 @@ endif
obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o
obj-$(CONFIG_SERIAL) += $(SERIAL)
obj-$(CONFIG_SERIAL_21285) += serial_21285.o
+obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o
+obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o
ifndef CONFIG_SUN_KEYBOARD
obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD)
@@ -158,26 +160,16 @@ obj-$(CONFIG_R3964) += n_r3964.o
obj-$(CONFIG_APPLICOM) += applicom.o
obj-$(CONFIG_MS_BUSMOUSE) += msbusmouse.o
obj-$(CONFIG_82C710_MOUSE) += qpmouse.o
-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
obj-$(CONFIG_PC110_PAD) += pc110pad.o
-obj-$(CONFIG_WDT) += wdt.o
-obj-$(CONFIG_WDTPCI) += wdt_pci.o
obj-$(CONFIG_RTC) += rtc.o
obj-$(CONFIG_EFI_RTC) += efirtc.o
ifeq ($(CONFIG_PPC),)
obj-$(CONFIG_NVRAM) += nvram.o
endif
-
-obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
-obj-$(CONFIG_977_WATCHDOG) += wdt977.o
-obj-$(CONFIG_I810_TCO) += i810-tco.o
+obj-$(CONFIG_TOSHIBA) += toshiba.o
obj-$(CONFIG_DS1620) += ds1620.o
obj-$(CONFIG_INTEL_RNG) += i810_rng.o
@@ -228,6 +220,23 @@ else
endif
endif
+# Only one watchdog can succeed. We probe the hardware watchdog
+# drivers first, then the softdog driver. This means if your hardware
+# watchdog dies or is 'borrowed' for some reason the software watchdog
+# still gives you some cover.
+
+obj-$(CONFIG_PCWATCHDOG) += pcwd.o
+obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
+obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
+obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
+obj-$(CONFIG_WDT) += wdt.o
+obj-$(CONFIG_WDTPCI) += wdt_pci.o
+obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
+obj-$(CONFIG_977_WATCHDOG) += wdt977.o
+obj-$(CONFIG_I810_TCO) += i810-tco.o
+obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
+
+
# Extract lists of the multi-part drivers.
# The 'int-*' lists are the intermediate files used to build the multi's.
diff --git a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
index b28df7e34..b685c4b85 100644
--- a/drivers/char/acquirewdt.c
+++ b/drivers/char/acquirewdt.c
@@ -204,21 +204,7 @@ static struct notifier_block acq_notifier=
0
};
-#ifdef MODULE
-
-#define acq_init init_module
-
-void cleanup_module(void)
-{
- misc_deregister(&acq_miscdev);
- unregister_reboot_notifier(&acq_notifier);
- release_region(WDT_STOP,1);
- release_region(WDT_START,1);
-}
-
-#endif
-
-int __init acq_init(void)
+static int __init acq_init(void)
{
printk("WDT driver for Acquire single board computer initialising.\n");
@@ -229,4 +215,14 @@ int __init acq_init(void)
register_reboot_notifier(&acq_notifier);
return 0;
}
+
+static void __exit acq_exit(void)
+{
+ misc_deregister(&acq_miscdev);
+ unregister_reboot_notifier(&acq_notifier);
+ release_region(WDT_STOP,1);
+ release_region(WDT_START,1);
+}
+module_init(acq_init);
+module_exit(acq_exit);
diff --git a/drivers/char/drm/agpsupport.c b/drivers/char/drm/agpsupport.c
index 42a1bc2f6..24fd59cdf 100644
--- a/drivers/char/drm/agpsupport.c
+++ b/drivers/char/drm/agpsupport.c
@@ -95,7 +95,8 @@ int drm_agp_info(struct inode *inode, struct file *filp, unsigned int cmd,
info.id_vendor = kern->device->vendor;
info.id_device = kern->device->device;
- copy_to_user_ret((drm_agp_info_t *)arg, &info, sizeof(info), -EFAULT);
+ if (copy_to_user((drm_agp_info_t *)arg, &info, sizeof(info)))
+ return -EFAULT;
return 0;
}
@@ -134,8 +135,8 @@ int drm_agp_enable(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dev->agp->acquired || !drm_agp.enable) return -EINVAL;
- copy_from_user_ret(&mode, (drm_agp_mode_t *)arg, sizeof(mode),
- -EFAULT);
+ if (copy_from_user(&mode, (drm_agp_mode_t *)arg, sizeof(mode)))
+ return -EFAULT;
dev->agp->mode = mode.mode;
(*drm_agp.enable)(mode.mode);
@@ -155,8 +156,8 @@ int drm_agp_alloc(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long pages;
u32 type;
if (!dev->agp->acquired) return -EINVAL;
- copy_from_user_ret(&request, (drm_agp_buffer_t *)arg, sizeof(request),
- -EFAULT);
+ if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request)))
+ return -EFAULT;
if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS)))
return -ENOMEM;
@@ -212,8 +213,8 @@ int drm_agp_unbind(struct inode *inode, struct file *filp, unsigned int cmd,
drm_agp_mem_t *entry;
if (!dev->agp->acquired) return -EINVAL;
- copy_from_user_ret(&request, (drm_agp_binding_t *)arg, sizeof(request),
- -EFAULT);
+ if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
+ return -EFAULT;
if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
return -EINVAL;
if (!entry->bound) return -EINVAL;
@@ -231,8 +232,8 @@ int drm_agp_bind(struct inode *inode, struct file *filp, unsigned int cmd,
int page;
if (!dev->agp->acquired || !drm_agp.bind_memory) return -EINVAL;
- copy_from_user_ret(&request, (drm_agp_binding_t *)arg, sizeof(request),
- -EFAULT);
+ if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
+ return -EFAULT;
if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
return -EINVAL;
if (entry->bound) return -EINVAL;
@@ -253,8 +254,8 @@ int drm_agp_free(struct inode *inode, struct file *filp, unsigned int cmd,
drm_agp_mem_t *entry;
if (!dev->agp->acquired) return -EINVAL;
- copy_from_user_ret(&request, (drm_agp_buffer_t *)arg, sizeof(request),
- -EFAULT);
+ if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request)))
+ return -EFAULT;
if (!(entry = drm_agp_lookup_entry(dev, request.handle)))
return -EINVAL;
if (entry->bound) drm_unbind_agp(entry->memory);
diff --git a/drivers/char/drm/auth.c b/drivers/char/drm/auth.c
index 4556bd966..80bb4b651 100644
--- a/drivers/char/drm/auth.c
+++ b/drivers/char/drm/auth.c
@@ -137,7 +137,8 @@ int drm_getmagic(struct inode *inode, struct file *filp, unsigned int cmd,
}
DRM_DEBUG("%u\n", auth.magic);
- copy_to_user_ret((drm_auth_t *)arg, &auth, sizeof(auth), -EFAULT);
+ if (copy_to_user((drm_auth_t *)arg, &auth, sizeof(auth)))
+ return -EFAULT;
return 0;
}
@@ -149,7 +150,8 @@ int drm_authmagic(struct inode *inode, struct file *filp, unsigned int cmd,
drm_auth_t auth;
drm_file_t *file;
- copy_from_user_ret(&auth, (drm_auth_t *)arg, sizeof(auth), -EFAULT);
+ if (copy_from_user(&auth, (drm_auth_t *)arg, sizeof(auth)))
+ return -EFAULT;
DRM_DEBUG("%u\n", auth.magic);
if ((file = drm_find_file(dev, auth.magic))) {
file->authenticated = 1;
diff --git a/drivers/char/drm/bufs.c b/drivers/char/drm/bufs.c
index c00f051a8..28e0eb5f1 100644
--- a/drivers/char/drm/bufs.c
+++ b/drivers/char/drm/bufs.c
@@ -133,12 +133,13 @@ int drm_addmap(struct inode *inode, struct file *filp, unsigned int cmd,
dev->maplist[dev->map_count-1] = map;
up(&dev->struct_sem);
- copy_to_user_ret((drm_map_t *)arg, map, sizeof(*map), -EFAULT);
+ if (copy_to_user((drm_map_t *)arg, map, sizeof(*map)))
+ return -EFAULT;
if (map->type != _DRM_SHM) {
- copy_to_user_ret(&((drm_map_t *)arg)->handle,
+ if (copy_to_user(&((drm_map_t *)arg)->handle,
&map->offset,
- sizeof(map->offset),
- -EFAULT);
+ sizeof(map->offset)))
+ return -EFAULT;
}
return 0;
}
@@ -166,10 +167,10 @@ int drm_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
count = request.count;
order = drm_order(request.size);
@@ -295,10 +296,10 @@ int drm_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
request.count = entry->buf_count;
request.size = size;
- copy_to_user_ret((drm_buf_desc_t *)arg,
+ if (copy_to_user((drm_buf_desc_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
atomic_dec(&dev->buf_alloc);
return 0;
@@ -324,10 +325,10 @@ int drm_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
++dev->buf_use; /* Can't allocate more after this call */
spin_unlock(&dev->count_lock);
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_info_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
if (dma->bufs[i].buf_count) ++count;
@@ -338,28 +339,26 @@ int drm_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (request.count >= count) {
for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
if (dma->bufs[i].buf_count) {
- copy_to_user_ret(&request.list[count].count,
+ if (copy_to_user(&request.list[count].count,
&dma->bufs[i].buf_count,
sizeof(dma->bufs[0]
- .buf_count),
- -EFAULT);
- copy_to_user_ret(&request.list[count].size,
+ .buf_count)) ||
+ copy_to_user(&request.list[count].size,
&dma->bufs[i].buf_size,
- sizeof(dma->bufs[0].buf_size),
- -EFAULT);
- copy_to_user_ret(&request.list[count].low_mark,
+ sizeof(dma->bufs[0].buf_size)) ||
+ copy_to_user(&request.list[count].low_mark,
&dma->bufs[i]
.freelist.low_mark,
sizeof(dma->bufs[0]
- .freelist.low_mark),
- -EFAULT);
- copy_to_user_ret(&request.list[count]
+ .freelist.low_mark)) ||
+ copy_to_user(&request.list[count]
.high_mark,
&dma->bufs[i]
.freelist.high_mark,
sizeof(dma->bufs[0]
- .freelist.high_mark),
- -EFAULT);
+ .freelist.high_mark)))
+ return -EFAULT;
+
DRM_DEBUG("%d %d %d %d %d\n",
i,
dma->bufs[i].buf_count,
@@ -372,10 +371,10 @@ int drm_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
}
request.count = count;
- copy_to_user_ret((drm_buf_info_t *)arg,
+ if (copy_to_user((drm_buf_info_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
return 0;
}
@@ -392,10 +391,10 @@ int drm_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
DRM_DEBUG("%d, %d, %d\n",
request.size, request.low_mark, request.high_mark);
@@ -427,17 +426,17 @@ int drm_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_free_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
DRM_DEBUG("%d\n", request.count);
for (i = 0; i < request.count; i++) {
- copy_from_user_ret(&idx,
+ if (copy_from_user(&idx,
&request.list[i],
- sizeof(idx),
- -EFAULT);
+ sizeof(idx)))
+ return -EFAULT;
if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("Index %d (of %d max)\n",
idx, dma->buf_count - 1);
@@ -480,10 +479,10 @@ int drm_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
++dev->buf_use; /* Can't allocate more after this call */
spin_unlock(&dev->count_lock);
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_map_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
if (request.count >= dma->buf_count) {
down(&current->mm->mmap_sem);
@@ -529,10 +528,10 @@ done:
request.count = dma->buf_count;
DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
- copy_to_user_ret((drm_buf_map_t *)arg,
+ if (copy_to_user((drm_buf_map_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
return retcode;
}
diff --git a/drivers/char/drm/context.c b/drivers/char/drm/context.c
index ca491094e..933fd0cd2 100644
--- a/drivers/char/drm/context.c
+++ b/drivers/char/drm/context.c
@@ -129,19 +129,21 @@ int drm_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
int i;
DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
- copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+ if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
+ return -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],
+ if (copy_to_user(&res.contexts[i],
&i,
- sizeof(i),
- -EFAULT);
+ sizeof(i)))
+ return -EFAULT;
}
}
res.count = DRM_RESERVED_CONTEXTS;
- copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+ if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
+ return -EFAULT;
return 0;
}
@@ -153,7 +155,8 @@ int drm_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
if ((ctx.handle = drm_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
/* Init kernel's context and get a new one. */
drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
@@ -161,7 +164,8 @@ int drm_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
}
drm_init_queue(dev, dev->queuelist[ctx.handle], &ctx);
DRM_DEBUG("%d\n", ctx.handle);
- copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -173,7 +177,8 @@ int drm_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_ctx_t ctx;
drm_queue_t *q;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
@@ -206,7 +211,8 @@ int drm_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_ctx_t ctx;
drm_queue_t *q;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
@@ -223,7 +229,8 @@ int drm_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
ctx.flags = q->flags;
atomic_dec(&q->use_count);
- copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -235,7 +242,8 @@ int drm_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
return drm_context_switch(dev, dev->last_context, ctx.handle);
}
@@ -247,7 +255,8 @@ int drm_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
drm_context_switch_complete(dev, ctx.handle);
@@ -263,7 +272,8 @@ int drm_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_queue_t *q;
drm_buf_t *buf;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
if (ctx.handle >= dev->queue_count) return -EINVAL;
diff --git a/drivers/char/drm/dma.c b/drivers/char/drm/dma.c
index ac2d1bc5a..5cc3ec369 100644
--- a/drivers/char/drm/dma.c
+++ b/drivers/char/drm/dma.c
@@ -397,10 +397,10 @@ int drm_dma_enqueue(drm_device_t *dev, drm_dma_t *d)
atomic_inc(&q->use_count);
if (atomic_read(&q->block_write)) {
- current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&q->write_queue, &entry);
atomic_inc(&q->block_count);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
if (!atomic_read(&q->block_write)) break;
schedule();
if (signal_pending(current)) {
@@ -486,14 +486,16 @@ static int drm_dma_get_buffers_of_order(drm_device_t *dev, drm_dma_t *d,
buf->pending);
}
buf->pid = current->pid;
- copy_to_user_ret(&d->request_indices[i],
+ if (copy_to_user(&d->request_indices[i],
&buf->idx,
- sizeof(buf->idx),
- -EFAULT);
- copy_to_user_ret(&d->request_sizes[i],
+ sizeof(buf->idx)))
+ return -EFAULT;
+
+ if (copy_to_user(&d->request_sizes[i],
&buf->total,
- sizeof(buf->total),
- -EFAULT);
+ sizeof(buf->total)))
+ return -EFAULT;
+
++d->granted_count;
}
return 0;
diff --git a/drivers/char/drm/drawable.c b/drivers/char/drm/drawable.c
index 03839f5be..1328054e2 100644
--- a/drivers/char/drm/drawable.c
+++ b/drivers/char/drm/drawable.c
@@ -39,7 +39,8 @@ int drm_adddraw(struct inode *inode, struct file *filp, unsigned int cmd,
draw.handle = 0; /* NOOP */
DRM_DEBUG("%d\n", draw.handle);
- copy_to_user_ret((drm_draw_t *)arg, &draw, sizeof(draw), -EFAULT);
+ if (copy_to_user((drm_draw_t *)arg, &draw, sizeof(draw)))
+ return -EFAULT;
return 0;
}
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 5a979e1cb..b182f2c99 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -35,7 +35,13 @@
#ifndef _DRM_H_
#define _DRM_H_
+#if defined(__linux__)
#include <asm/ioctl.h> /* For _IO* macros */
+#define DRM_IOCTL_NR(n) _IOC_NR(n)
+#elif defined(__FreeBSD__)
+#include <sys/ioccom.h>
+#define DRM_IOCTL_NR(n) ((n) & 0xff)
+#endif
#define DRM_PROC_DEVICES "/proc/devices"
#define DRM_PROC_MISC "/proc/misc"
@@ -289,7 +295,6 @@ typedef struct drm_agp_info {
} drm_agp_info_t;
#define DRM_IOCTL_BASE 'd'
-#define DRM_IOCTL_NR(n) _IOC_NR(n)
#define DRM_IO(nr) _IO(DRM_IOCTL_BASE,nr)
#define DRM_IOR(nr,size) _IOR(DRM_IOCTL_BASE,nr,size)
#define DRM_IOW(nr,size) _IOW(DRM_IOCTL_BASE,nr,size)
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index e8ec9bdbc..6be90c516 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -33,6 +33,12 @@
#define _DRM_P_H_
#ifdef __KERNEL__
+#ifdef __alpha__
+/* add include of current.h so that "current" is defined
+ * before static inline funcs in wait.h. Doing this so we
+ * can build the DRM (part of PI DRI). 4/21/2000 S + B */
+#include <asm/current.h>
+#endif /* __alpha__ */
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -47,6 +53,9 @@
#include <linux/sched.h>
#include <linux/smp_lock.h> /* For (un)lock_kernel */
#include <linux/mm.h>
+#ifdef __alpha__
+#include <asm/pgtable.h> /* For pte_wrprotect */
+#endif
#include <asm/io.h>
#include <asm/mman.h>
#include <asm/uaccess.h>
@@ -57,10 +66,13 @@
#include <linux/types.h>
#include <linux/agp_backend.h>
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+#if LINUX_VERSION_CODE >= 0x020100 /* KERNEL_VERSION(2,1,0) */
#include <linux/tqueue.h>
#include <linux/poll.h>
#endif
+#if LINUX_VERSION_CODE < 0x020400
+#include "compat-pre24.h"
+#endif
#include "drm.h"
#define DRM_DEBUG_CODE 2 /* Include debugging code (if > 1, then
@@ -140,15 +152,75 @@ typedef struct wait_queue *wait_queue_head_t;
#define module_exit(x) void cleanup_module(void) { x(); }
#endif
- /* virt_to_page added in 2.4.0-test6 */
-#if LINUX_VERSION_CODE < 0x020400
-#define virt_to_page(kaddr) (mem_map + MAP_NR(kaddr))
-#endif
-
/* Generic cmpxchg added in 2.3.x */
#ifndef __HAVE_ARCH_CMPXCHG
/* Include this here so that driver can be
used with older kernels. */
+#if defined(__alpha__)
+static __inline__ unsigned long
+__cmpxchg_u32(volatile int *m, int old, int new)
+{
+ unsigned long prev, cmp;
+
+ __asm__ __volatile__(
+ "1: ldl_l %0,%2\n"
+ " cmpeq %0,%3,%1\n"
+ " beq %1,2f\n"
+ " mov %4,%1\n"
+ " stl_c %1,%2\n"
+ " beq %1,3f\n"
+ "2: mb\n"
+ ".subsection 2\n"
+ "3: br 1b\n"
+ ".previous"
+ : "=&r"(prev), "=&r"(cmp), "=m"(*m)
+ : "r"((long) old), "r"(new), "m"(*m));
+
+ return prev;
+}
+
+static __inline__ unsigned long
+__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
+{
+ unsigned long prev, cmp;
+
+ __asm__ __volatile__(
+ "1: ldq_l %0,%2\n"
+ " cmpeq %0,%3,%1\n"
+ " beq %1,2f\n"
+ " mov %4,%1\n"
+ " stq_c %1,%2\n"
+ " beq %1,3f\n"
+ "2: mb\n"
+ ".subsection 2\n"
+ "3: br 1b\n"
+ ".previous"
+ : "=&r"(prev), "=&r"(cmp), "=m"(*m)
+ : "r"((long) old), "r"(new), "m"(*m));
+
+ return prev;
+}
+
+static __inline__ unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+{
+ switch (size) {
+ case 4:
+ return __cmpxchg_u32(ptr, old, new);
+ case 8:
+ return __cmpxchg_u64(ptr, old, new);
+ }
+ return old;
+}
+#define cmpxchg(ptr,o,n) \
+ ({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \
+ (unsigned long)_n_, sizeof(*(ptr))); \
+ })
+
+#elif __i386__
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
unsigned long new, int size)
{
@@ -179,6 +251,7 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
#define cmpxchg(ptr,o,n) \
((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o), \
(unsigned long)(n),sizeof(*(ptr))))
+#endif /* i386 & alpha */
#endif
/* Macros to make printk easier */
@@ -357,6 +430,7 @@ typedef struct drm_file {
struct drm_file *next;
struct drm_file *prev;
struct drm_device *dev;
+ int remove_auth_on_close;
} drm_file_t;
diff --git a/drivers/char/drm/ffb_context.c b/drivers/char/drm/ffb_context.c
index a10b59898..4e8b29b73 100644
--- a/drivers/char/drm/ffb_context.c
+++ b/drivers/char/drm/ffb_context.c
@@ -1,4 +1,4 @@
-/* $Id: ffb_context.c,v 1.3 2000/06/09 03:46:53 davem Exp $
+/* $Id: ffb_context.c,v 1.4 2000/08/29 07:01:55 davem Exp $
* ffb_context.c: Creator/Creator3D DRI/DRM context switching.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -389,19 +389,21 @@ int ffb_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
int i;
DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
- copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+ if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
+ return -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],
+ if (copy_to_user(&res.contexts[i],
&i,
- sizeof(i),
- -EFAULT);
+ sizeof(i)))
+ return -EFAULT;
}
}
res.count = DRM_RESERVED_CONTEXTS;
- copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+ if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
+ return -EFAULT;
return 0;
}
@@ -414,14 +416,16 @@ int ffb_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_ctx_t ctx;
int idx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -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);
+ if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -435,7 +439,8 @@ int ffb_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_ctx_t ctx;
int idx;
- copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+ return -EFAULT;
idx = ctx.handle;
if (idx <= 0 || idx >= FFB_MAX_CTXS)
@@ -463,7 +468,8 @@ int ffb_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_ctx_t ctx;
int idx;
- copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+ return -EFAULT;
idx = ctx.handle;
if (idx <= 0 || idx >= FFB_MAX_CTXS)
@@ -478,7 +484,8 @@ int ffb_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
else
ctx.flags = 0;
- copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -490,7 +497,8 @@ int ffb_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
return ffb_context_switch(dev, dev->last_context, ctx.handle);
}
@@ -500,7 +508,8 @@ int ffb_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
{
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
return 0;
@@ -515,7 +524,8 @@ int ffb_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
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);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
idx = ctx.handle - 1;
diff --git a/drivers/char/drm/fops.c b/drivers/char/drm/fops.c
index f3966d96b..8e373e5ad 100644
--- a/drivers/char/drm/fops.c
+++ b/drivers/char/drm/fops.c
@@ -176,7 +176,8 @@ ssize_t drm_read(struct file *filp, char *buf, size_t count, loff_t *off)
} else {
cur = DRM_MIN(send, dev->buf_end - dev->buf_rp);
}
- copy_to_user_ret(buf, dev->buf_rp, cur, -EINVAL);
+ if (copy_to_user(buf, dev->buf_rp, cur))
+ return -EFAULT;
dev->buf_rp += cur;
if (dev->buf_rp == dev->buf_end) dev->buf_rp = dev->buf;
send -= cur;
diff --git a/drivers/char/drm/gamma_dma.c b/drivers/char/drm/gamma_dma.c
index a99f24cae..4ab67281c 100644
--- a/drivers/char/drm/gamma_dma.c
+++ b/drivers/char/drm/gamma_dma.c
@@ -542,10 +542,9 @@ static int gamma_dma_send_buffers(drm_device_t *dev, drm_dma_t *d)
if (d->flags & _DRM_DMA_BLOCK) {
DRM_DEBUG("%d waiting\n", current->pid);
- current->state = TASK_INTERRUPTIBLE;
for (;;) {
- if (!last_buf->waiting
- && !last_buf->pending)
+ current->state = TASK_INTERRUPTIBLE;
+ if (!last_buf->waiting && !last_buf->pending)
break; /* finished */
schedule();
if (signal_pending(current)) {
@@ -586,7 +585,8 @@ int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd,
int retcode = 0;
drm_dma_t d;
- copy_from_user_ret(&d, (drm_dma_t *)arg, sizeof(d), -EFAULT);
+ if (copy_from_user(&d, (drm_dma_t *)arg, sizeof(d)))
+ return -EFAULT;
DRM_DEBUG("%d %d: %d send, %d req\n",
current->pid, d.context, d.send_count, d.request_count);
@@ -621,7 +621,8 @@ int gamma_dma(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_DEBUG("%d returning, granted = %d\n",
current->pid, d.granted_count);
- copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
+ if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
+ return -EFAULT;
return retcode;
}
@@ -710,7 +711,8 @@ int gamma_control(struct inode *inode, struct file *filp, unsigned int cmd,
drm_control_t ctl;
int retcode;
- copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT);
+ if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl)))
+ return -EFAULT;
switch (ctl.func) {
case DRM_INST_HANDLER:
@@ -742,7 +744,8 @@ int gamma_lock(struct inode *inode, struct file *filp, unsigned int cmd,
dev->lck_start = start = get_cycles();
#endif
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
@@ -774,6 +777,7 @@ int gamma_lock(struct inode *inode, struct file *filp, unsigned int cmd,
}
add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
if (!dev->lock.hw_lock) {
/* Device has been unregistered */
ret = -EINTR;
@@ -790,7 +794,6 @@ int gamma_lock(struct inode *inode, struct file *filp, unsigned int cmd,
/* Contention */
atomic_inc(&dev->total_sleeps);
- current->state = TASK_INTERRUPTIBLE;
schedule();
if (signal_pending(current)) {
ret = -ERESTARTSYS;
@@ -804,6 +807,15 @@ int gamma_lock(struct inode *inode, struct file *filp, unsigned int cmd,
drm_flush_unblock(dev, lock.context, lock.flags); /* cleanup phase */
if (!ret) {
+ sigemptyset(&dev->sigmask);
+ sigaddset(&dev->sigmask, SIGSTOP);
+ sigaddset(&dev->sigmask, SIGTSTP);
+ sigaddset(&dev->sigmask, SIGTTIN);
+ sigaddset(&dev->sigmask, SIGTTOU);
+ dev->sigdata.context = lock.context;
+ dev->sigdata.lock = dev->lock.hw_lock;
+ block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
+
if (lock.flags & _DRM_LOCK_READY)
gamma_dma_ready(dev);
if (lock.flags & _DRM_LOCK_QUIESCENT) {
diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c
index 13d37c245..dba974c2b 100644
--- a/drivers/char/drm/gamma_drv.c
+++ b/drivers/char/drm/gamma_drv.c
@@ -11,11 +11,11 @@
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
@@ -23,7 +23,7 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
- *
+ *
* Authors:
* Rickard E. (Rik) Faith <faith@valinux.com>
*
@@ -42,7 +42,7 @@
#define GAMMA_NAME "gamma"
#define GAMMA_DESC "3dlabs GMX 2000"
-#define GAMMA_DATE "20000719"
+#define GAMMA_DATE "20000910"
#define GAMMA_MAJOR 1
#define GAMMA_MINOR 0
#define GAMMA_PATCHLEVEL 0
@@ -87,7 +87,7 @@ static drm_ioctl_desc_t gamma_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS)] = { drm_infobufs, 1, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS)] = { drm_mapbufs, 1, 0 },
[DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS)] = { drm_freebufs, 1, 0 },
-
+
[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { drm_addctx, 1, 1 },
[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { drm_rmctx, 1, 1 },
[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { drm_modctx, 1, 1 },
@@ -120,7 +120,7 @@ MODULE_PARM_DESC(devices,
* passed via the boot-loader (e.g., LILO). It calls the insmod option
* routine, drm_parse_options.
*/
-
+
static int __init gamma_options(char *str)
{
@@ -134,7 +134,7 @@ __setup("gamma=", gamma_options);
static int gamma_setup(drm_device_t *dev)
{
int i;
-
+
atomic_set(&dev->ioctl_count, 0);
atomic_set(&dev->vma_count, 0);
dev->buf_use = 0;
@@ -179,22 +179,22 @@ static int gamma_setup(drm_device_t *dev)
#endif
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);
-
+
DRM_DEBUG("\n");
-
+
/* The kernel's context could be created here, but is now created
in drm_dma_enqueue. This is more resource-efficient for
hardware that does not do DMA, but may mean that
drm_select_queue fails between the time the interrupt is
initialized and the time the queues are initialized. */
-
+
return 0;
}
@@ -209,15 +209,15 @@ static int gamma_takedown(drm_device_t *dev)
DRM_DEBUG("\n");
if (dev->irq) gamma_irq_uninstall(dev);
-
+
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;
@@ -231,7 +231,7 @@ static int gamma_takedown(drm_device_t *dev)
}
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) {
@@ -240,7 +240,7 @@ static int gamma_takedown(drm_device_t *dev)
}
dev->vmalist = NULL;
}
-
+
/* Clear map area and mtrr information */
if (dev->maplist) {
for (i = 0; i < dev->map_count; i++) {
@@ -278,7 +278,7 @@ static int gamma_takedown(drm_device_t *dev)
dev->maplist = NULL;
dev->map_count = 0;
}
-
+
if (dev->queuelist) {
for (i = 0; i < dev->queue_count; i++) {
drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
@@ -304,7 +304,7 @@ static int gamma_takedown(drm_device_t *dev)
wake_up_interruptible(&dev->lock.lock_queue);
}
up(&dev->struct_sem);
-
+
return 0;
}
@@ -349,7 +349,7 @@ static int gamma_init(void)
memset((void *)dev, 0, sizeof(*dev));
dev->count_lock = SPIN_LOCK_UNLOCKED;
sema_init(&dev->struct_sem, 1);
-
+
#ifdef MODULE
drm_parse_options(gamma);
#endif
@@ -374,7 +374,7 @@ static int gamma_init(void)
GAMMA_DATE,
gamma_misc.minor,
devices);
-
+
return 0;
}
@@ -385,7 +385,7 @@ static void gamma_cleanup(void)
drm_device_t *dev = &gamma_device;
DRM_DEBUG("\n");
-
+
drm_proc_cleanup();
if (misc_deregister(&gamma_misc)) {
DRM_ERROR("Cannot unload module\n");
@@ -405,17 +405,18 @@ int gamma_version(struct inode *inode, struct file *filp, unsigned int cmd,
drm_version_t version;
int len;
- copy_from_user_ret(&version,
+ if (copy_from_user(&version,
(drm_version_t *)arg,
- sizeof(version),
- -EFAULT);
+ sizeof(version)))
+ return -EFAULT;
#define DRM_COPY(name,value) \
len = strlen(value); \
if (len > name##_len) len = name##_len; \
name##_len = strlen(value); \
if (len && name) { \
- copy_to_user_ret(name, value, len, -EFAULT); \
+ if (copy_to_user(name, value, len)) \
+ return -EFAULT; \
}
version.version_major = GAMMA_MAJOR;
@@ -426,10 +427,10 @@ int gamma_version(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_COPY(version.date, GAMMA_DATE);
DRM_COPY(version.desc, GAMMA_DESC);
- copy_to_user_ret((drm_version_t *)arg,
+ if (copy_to_user((drm_version_t *)arg,
&version,
- sizeof(version),
- -EFAULT);
+ sizeof(version)))
+ return -EFAULT;
return 0;
}
@@ -437,7 +438,7 @@ int gamma_open(struct inode *inode, struct file *filp)
{
drm_device_t *dev = &gamma_device;
int retcode = 0;
-
+
DRM_DEBUG("open_count = %d\n", dev->open_count);
if (!(retcode = drm_open_helper(inode, filp, dev))) {
#if LINUX_VERSION_CODE < 0x020333
@@ -504,7 +505,7 @@ int gamma_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
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);
@@ -524,7 +525,7 @@ int gamma_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
retcode = (func)(inode, filp, cmd, arg);
}
}
-
+
atomic_dec(&dev->ioctl_count);
return retcode;
}
@@ -537,8 +538,9 @@ int gamma_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_lock_t lock;
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
-
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
+
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
current->pid, lock.context);
@@ -563,6 +565,7 @@ int gamma_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles()
- dev->lck_start)]);
#endif
-
+
+ unblock_all_signals();
return 0;
}
diff --git a/drivers/char/drm/i810_bufs.c b/drivers/char/drm/i810_bufs.c
index fa1f84dcd..a999e96b9 100644
--- a/drivers/char/drm/i810_bufs.c
+++ b/drivers/char/drm/i810_bufs.c
@@ -56,10 +56,10 @@ int i810_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
count = request.count;
order = drm_order(request.size);
@@ -155,10 +155,10 @@ int i810_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
request.count = entry->buf_count;
request.size = size;
- copy_to_user_ret((drm_buf_desc_t *)arg,
+ if (copy_to_user((drm_buf_desc_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
atomic_dec(&dev->buf_alloc);
dma->flags = _DRM_DMA_USE_AGP;
@@ -170,10 +170,10 @@ int i810_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
{
drm_buf_desc_t request;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
if(request.flags & _DRM_AGP_BUFFER)
return i810_addbufs_agp(inode, filp, cmd, arg);
@@ -201,10 +201,10 @@ int i810_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
++dev->buf_use; /* Can't allocate more after this call */
spin_unlock(&dev->count_lock);
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_info_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
if (dma->bufs[i].buf_count) ++count;
@@ -215,28 +215,26 @@ int i810_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (request.count >= count) {
for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
if (dma->bufs[i].buf_count) {
- copy_to_user_ret(&request.list[count].count,
+ if (copy_to_user(&request.list[count].count,
&dma->bufs[i].buf_count,
sizeof(dma->bufs[0]
- .buf_count),
- -EFAULT);
- copy_to_user_ret(&request.list[count].size,
+ .buf_count)) ||
+ copy_to_user(&request.list[count].size,
&dma->bufs[i].buf_size,
- sizeof(dma->bufs[0].buf_size),
- -EFAULT);
- copy_to_user_ret(&request.list[count].low_mark,
+ sizeof(dma->bufs[0].buf_size)) ||
+ copy_to_user(&request.list[count].low_mark,
&dma->bufs[i]
.freelist.low_mark,
sizeof(dma->bufs[0]
- .freelist.low_mark),
- -EFAULT);
- copy_to_user_ret(&request.list[count]
+ .freelist.low_mark)) ||
+ copy_to_user(&request.list[count]
.high_mark,
&dma->bufs[i]
.freelist.high_mark,
sizeof(dma->bufs[0]
- .freelist.high_mark),
- -EFAULT);
+ .freelist.high_mark)))
+ return -EFAULT;
+
DRM_DEBUG("%d %d %d %d %d\n",
i,
dma->bufs[i].buf_count,
@@ -249,10 +247,10 @@ int i810_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
}
request.count = count;
- copy_to_user_ret((drm_buf_info_t *)arg,
+ if (copy_to_user((drm_buf_info_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
return 0;
}
@@ -269,10 +267,10 @@ int i810_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
DRM_DEBUG("%d, %d, %d\n",
request.size, request.low_mark, request.high_mark);
@@ -304,17 +302,17 @@ int i810_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_free_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
DRM_DEBUG("%d\n", request.count);
for (i = 0; i < request.count; i++) {
- copy_from_user_ret(&idx,
+ if (copy_from_user(&idx,
&request.list[i],
- sizeof(idx),
- -EFAULT);
+ sizeof(idx)))
+ return -EFAULT;
if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("Index %d (of %d max)\n",
idx, dma->buf_count - 1);
diff --git a/drivers/char/drm/i810_context.c b/drivers/char/drm/i810_context.c
index 85c0877b6..c331beed6 100644
--- a/drivers/char/drm/i810_context.c
+++ b/drivers/char/drm/i810_context.c
@@ -103,19 +103,21 @@ int i810_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
int i;
DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
- copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+ if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
+ return -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],
+ if (copy_to_user(&res.contexts[i],
&i,
- sizeof(i),
- -EFAULT);
+ sizeof(i)))
+ return -EFAULT;
}
}
res.count = DRM_RESERVED_CONTEXTS;
- copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+ if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
+ return -EFAULT;
return 0;
}
@@ -126,7 +128,8 @@ int i810_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
if ((ctx.handle = i810_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
/* Skip kernel's context and get a new one. */
ctx.handle = i810_alloc_queue(dev);
@@ -137,7 +140,8 @@ int i810_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
return -ENOMEM;
}
DRM_DEBUG("%d\n", ctx.handle);
- copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -153,10 +157,12 @@ int i810_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
{
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+ return -EFAULT;
/* This is 0, because we don't hanlde any context flags */
ctx.flags = 0;
- copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -167,7 +173,8 @@ int i810_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
return i810_context_switch(dev, dev->last_context, ctx.handle);
}
@@ -179,7 +186,8 @@ int i810_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
i810_context_switch_complete(dev, ctx.handle);
@@ -193,7 +201,8 @@ int i810_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
if(ctx.handle != DRM_KERNEL_CONTEXT) {
drm_ctxbitmap_free(dev, ctx.handle);
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index 19b7bd928..26fe0c1c1 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -252,16 +252,15 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,
buf = i810_freelist_get(dev);
if (!buf) {
retcode = -ENOMEM;
- DRM_DEBUG("%s retcode %d\n", __FUNCTION__, retcode);
- goto out_get_buf;
+ DRM_DEBUG("retcode=%d\n", retcode);
+ return retcode;
}
retcode = i810_map_buffer(buf, filp);
if(retcode) {
i810_freelist_put(dev, buf);
- DRM_DEBUG("mapbuf failed in %s retcode %d\n",
- __FUNCTION__, retcode);
- goto out_get_buf;
+ DRM_DEBUG("mapbuf failed, retcode %d\n", retcode);
+ return retcode;
}
buf->pid = priv->pid;
buf_priv = buf->dev_private;
@@ -270,7 +269,6 @@ static int i810_dma_get_buffer(drm_device_t *dev, drm_i810_dma_t *d,
d->request_size = buf->total;
d->virtual = buf_priv->virtual;
-out_get_buf:
return retcode;
}
@@ -490,8 +488,8 @@ int i810_dma_init(struct inode *inode, struct file *filp,
drm_i810_init_t init;
int retcode = 0;
- copy_from_user_ret(&init, (drm_i810_init_t *)arg,
- sizeof(init), -EFAULT);
+ if (copy_from_user(&init, (drm_i810_init_t *)arg, sizeof(init)))
+ return -EFAULT;
switch(init.func) {
case I810_INIT_DMA:
@@ -1005,7 +1003,8 @@ int i810_control(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_DEBUG( "i810_control\n");
- copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT);
+ if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl)))
+ return -EFAULT;
switch (ctl.func) {
case DRM_INST_HANDLER:
@@ -1068,11 +1067,11 @@ static void i810_dma_quiescent(drm_device_t *dev)
return;
}
atomic_set(&dev_priv->flush_done, 0);
- current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&dev_priv->flush_queue, &entry);
end = jiffies + (HZ*3);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
i810_dma_quiescent_emit(dev);
if (atomic_read(&dev_priv->flush_done) == 1) break;
if((signed)(end - jiffies) <= 0) {
@@ -1103,10 +1102,10 @@ static int i810_flush_queue(drm_device_t *dev)
return 0;
}
atomic_set(&dev_priv->flush_done, 0);
- current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&dev_priv->flush_queue, &entry);
end = jiffies + (HZ*3);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
i810_dma_emit_flush(dev);
if (atomic_read(&dev_priv->flush_done) == 1) break;
if((signed)(end - jiffies) <= 0) {
@@ -1178,7 +1177,8 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
int ret = 0;
drm_lock_t lock;
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
@@ -1199,6 +1199,7 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
if (!ret) {
add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
if (!dev->lock.hw_lock) {
/* Device has been unregistered */
ret = -EINTR;
@@ -1214,7 +1215,6 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
/* Contention */
atomic_inc(&dev->total_sleeps);
- current->state = TASK_INTERRUPTIBLE;
DRM_DEBUG("Calling lock schedule\n");
schedule();
if (signal_pending(current)) {
@@ -1227,6 +1227,15 @@ int i810_lock(struct inode *inode, struct file *filp, unsigned int cmd,
}
if (!ret) {
+ sigemptyset(&dev->sigmask);
+ sigaddset(&dev->sigmask, SIGSTOP);
+ sigaddset(&dev->sigmask, SIGTSTP);
+ sigaddset(&dev->sigmask, SIGTTIN);
+ sigaddset(&dev->sigmask, SIGTTOU);
+ dev->sigdata.context = lock.context;
+ dev->sigdata.lock = dev->lock.hw_lock;
+ block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
+
if (lock.flags & _DRM_LOCK_QUIESCENT) {
DRM_DEBUG("_DRM_LOCK_QUIESCENT\n");
DRM_DEBUG("fred\n");
@@ -1266,8 +1275,8 @@ int i810_dma_vertex(struct inode *inode, struct file *filp,
dev_priv->sarea_priv;
drm_i810_vertex_t vertex;
- copy_from_user_ret(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex),
- -EFAULT);
+ if (copy_from_user(&vertex, (drm_i810_vertex_t *)arg, sizeof(vertex)))
+ return -EFAULT;
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("i810_dma_vertex called without lock held\n");
@@ -1298,8 +1307,8 @@ int i810_clear_bufs(struct inode *inode, struct file *filp,
drm_device_t *dev = priv->dev;
drm_i810_clear_t clear;
- copy_from_user_ret(&clear, (drm_i810_clear_t *)arg, sizeof(clear),
- -EFAULT);
+ if (copy_from_user(&clear, (drm_i810_clear_t *)arg, sizeof(clear)))
+ return -EFAULT;
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("i810_clear_bufs called without lock held\n");
@@ -1356,7 +1365,8 @@ int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
dev_priv->sarea_priv;
DRM_DEBUG("getbuf\n");
- copy_from_user_ret(&d, (drm_i810_dma_t *)arg, sizeof(d), -EFAULT);
+ if (copy_from_user(&d, (drm_i810_dma_t *)arg, sizeof(d)))
+ return -EFAULT;
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("i810_dma called without lock held\n");
@@ -1370,7 +1380,8 @@ int i810_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_DEBUG("i810_dma: %d returning %d, granted = %d\n",
current->pid, retcode, d.granted);
- copy_to_user_ret((drm_dma_t *)arg, &d, sizeof(d), -EFAULT);
+ if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
+ return -EFAULT;
sarea_priv->last_dispatch = (int) hw_status[5];
return retcode;
@@ -1395,14 +1406,16 @@ int i810_copybuf(struct inode *inode, struct file *filp, unsigned int cmd,
return -EINVAL;
}
- copy_from_user_ret(&d, (drm_i810_copy_t *)arg, sizeof(d), -EFAULT);
+ if (copy_from_user(&d, (drm_i810_copy_t *)arg, sizeof(d)))
+ return -EFAULT;
if(d.idx > dma->buf_count) return -EINVAL;
buf = dma->buflist[ d.idx ];
buf_priv = buf->dev_private;
if (buf_priv->currently_mapped != I810_BUF_MAPPED) return -EPERM;
- copy_from_user_ret(buf_priv->virtual, d.address, d.used, -EFAULT);
+ if (copy_from_user(buf_priv->virtual, d.address, d.used))
+ return -EFAULT;
sarea_priv->last_dispatch = (int) hw_status[5];
diff --git a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c
index 275663a1b..ed880c41a 100644
--- a/drivers/char/drm/i810_drv.c
+++ b/drivers/char/drm/i810_drv.c
@@ -1,6 +1,6 @@
/* i810_drv.c -- I810 driver -*- linux-c -*-
* Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
- *
+ *
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
@@ -11,11 +11,11 @@
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
@@ -35,7 +35,7 @@
#define I810_NAME "i810"
#define I810_DESC "Intel I810"
-#define I810_DATE "20000719"
+#define I810_DATE "20000928"
#define I810_MAJOR 1
#define I810_MINOR 1
#define I810_PATCHLEVEL 0
@@ -143,7 +143,7 @@ __setup("i810=", i810_options);
static int i810_setup(drm_device_t *dev)
{
int i;
-
+
atomic_set(&dev->ioctl_count, 0);
atomic_set(&dev->vma_count, 0);
dev->buf_use = 0;
@@ -188,22 +188,22 @@ static int i810_setup(drm_device_t *dev)
#endif
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);
-
+
DRM_DEBUG("\n");
-
+
/* The kernel's context could be created here, but is now created
in drm_dma_enqueue. This is more resource-efficient for
hardware that does not do DMA, but may mean that
drm_select_queue fails between the time the interrupt is
initialized and the time the queues are initialized. */
-
+
return 0;
}
@@ -218,15 +218,15 @@ static int i810_takedown(drm_device_t *dev)
DRM_DEBUG("\n");
if (dev->irq) i810_irq_uninstall(dev);
-
+
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;
@@ -244,7 +244,7 @@ static int i810_takedown(drm_device_t *dev)
if (dev->agp) {
drm_agp_mem_t *entry;
drm_agp_mem_t *nexte;
-
+
/* Remove AGP resources, but leave dev->agp
intact until r128_cleanup is called. */
for (entry = dev->agp->memory; entry; entry = nexte) {
@@ -254,10 +254,10 @@ static int i810_takedown(drm_device_t *dev)
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
}
dev->agp->memory = NULL;
-
+
if (dev->agp->acquired && drm_agp.release)
(*drm_agp.release)();
-
+
dev->agp->acquired = 0;
dev->agp->enabled = 0;
}
@@ -269,7 +269,7 @@ static int i810_takedown(drm_device_t *dev)
}
dev->vmalist = NULL;
}
-
+
/* Clear map area and mtrr information */
if (dev->maplist) {
for (i = 0; i < dev->map_count; i++) {
@@ -305,7 +305,7 @@ static int i810_takedown(drm_device_t *dev)
dev->maplist = NULL;
dev->map_count = 0;
}
-
+
if (dev->queuelist) {
for (i = 0; i < dev->queue_count; i++) {
drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
@@ -331,7 +331,7 @@ static int i810_takedown(drm_device_t *dev)
wake_up_interruptible(&dev->lock.lock_queue);
}
up(&dev->struct_sem);
-
+
return 0;
}
@@ -348,7 +348,7 @@ static int i810_init(void)
memset((void *)dev, 0, sizeof(*dev));
dev->count_lock = SPIN_LOCK_UNLOCKED;
sema_init(&dev->struct_sem, 1);
-
+
#ifdef MODULE
drm_parse_options(i810);
#endif
@@ -402,7 +402,7 @@ static void i810_cleanup(void)
drm_device_t *dev = &i810_device;
DRM_DEBUG("\n");
-
+
drm_proc_cleanup();
if (misc_deregister(&i810_misc)) {
DRM_ERROR("Cannot unload module\n");
@@ -428,17 +428,18 @@ int i810_version(struct inode *inode, struct file *filp, unsigned int cmd,
drm_version_t version;
int len;
- copy_from_user_ret(&version,
+ if (copy_from_user(&version,
(drm_version_t *)arg,
- sizeof(version),
- -EFAULT);
+ sizeof(version)))
+ return -EFAULT;
#define DRM_COPY(name,value) \
len = strlen(value); \
if (len > name##_len) len = name##_len; \
name##_len = strlen(value); \
if (len && name) { \
- copy_to_user_ret(name, value, len, -EFAULT); \
+ if (copy_to_user(name, value, len)) \
+ return -EFAULT; \
}
version.version_major = I810_MAJOR;
@@ -449,10 +450,10 @@ int i810_version(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_COPY(version.date, I810_DATE);
DRM_COPY(version.desc, I810_DESC);
- copy_to_user_ret((drm_version_t *)arg,
+ if (copy_to_user((drm_version_t *)arg,
&version,
- sizeof(version),
- -EFAULT);
+ sizeof(version)))
+ return -EFAULT;
return 0;
}
@@ -460,7 +461,7 @@ int i810_open(struct inode *inode, struct file *filp)
{
drm_device_t *dev = &i810_device;
int retcode = 0;
-
+
DRM_DEBUG("open_count = %d\n", dev->open_count);
if (!(retcode = drm_open_helper(inode, filp, dev))) {
#if LINUX_VERSION_CODE < 0x020333
@@ -497,7 +498,7 @@ int i810_release(struct inode *inode, struct file *filp)
drm_lock_free(dev,
&dev->lock.hw_lock->lock,
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-
+
/* FIXME: may require heavy-handed reset of
hardware at this point, possibly
processed via a callback to the X
@@ -507,6 +508,7 @@ int i810_release(struct inode *inode, struct file *filp)
DECLARE_WAITQUEUE(entry, current);
add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
if (!dev->lock.hw_lock) {
/* Device has been unregistered */
retcode = -EINTR;
@@ -518,10 +520,9 @@ int i810_release(struct inode *inode, struct file *filp)
dev->lock.lock_time = jiffies;
atomic_inc(&dev->total_locks);
break; /* Got lock */
- }
+ }
/* Contention */
atomic_inc(&dev->total_sleeps);
- current->state = TASK_INTERRUPTIBLE;
schedule();
if (signal_pending(current)) {
retcode = -ERESTARTSYS;
@@ -544,7 +545,7 @@ int i810_release(struct inode *inode, struct file *filp)
if (priv->next) priv->next->prev = priv->prev;
else dev->file_last = priv->prev;
up(&dev->struct_sem);
-
+
drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
#if LINUX_VERSION_CODE < 0x020333
MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
@@ -584,7 +585,7 @@ int i810_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
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);
@@ -604,7 +605,7 @@ int i810_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
retcode = (func)(inode, filp, cmd, arg);
}
}
-
+
atomic_dec(&dev->ioctl_count);
return retcode;
}
@@ -616,8 +617,9 @@ int i810_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_lock_t lock;
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
-
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
+
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
current->pid, lock.context);
@@ -641,6 +643,7 @@ int i810_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
atomic_inc(&dev->histo.lhld[drm_histogram_slot(get_cycles()
- dev->lck_start)]);
#endif
-
+
+ unblock_all_signals();
return 0;
}
diff --git a/drivers/char/drm/ioctl.c b/drivers/char/drm/ioctl.c
index b246f76e5..2f4286b1c 100644
--- a/drivers/char/drm/ioctl.c
+++ b/drivers/char/drm/ioctl.c
@@ -38,13 +38,15 @@ int drm_irq_busid(struct inode *inode, struct file *filp, unsigned int cmd,
drm_irq_busid_t p;
struct pci_dev *dev;
- copy_from_user_ret(&p, (drm_irq_busid_t *)arg, sizeof(p), -EFAULT);
+ if (copy_from_user(&p, (drm_irq_busid_t *)arg, sizeof(p)))
+ return -EFAULT;
dev = pci_find_slot(p.busnum, PCI_DEVFN(p.devnum, p.funcnum));
if (dev) p.irq = dev->irq;
else p.irq = 0;
DRM_DEBUG("%d:%d:%d => IRQ %d\n",
p.busnum, p.devnum, p.funcnum, p.irq);
- copy_to_user_ret((drm_irq_busid_t *)arg, &p, sizeof(p), -EFAULT);
+ if (copy_to_user((drm_irq_busid_t *)arg, &p, sizeof(p)))
+ return -EFAULT;
return 0;
}
@@ -55,13 +57,15 @@ int drm_getunique(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_unique_t u;
- copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT);
+ if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u)))
+ return -EFAULT;
if (u.unique_len >= dev->unique_len) {
- copy_to_user_ret(u.unique, dev->unique, dev->unique_len,
- -EFAULT);
+ if (copy_to_user(u.unique, dev->unique, dev->unique_len))
+ return -EFAULT;
}
u.unique_len = dev->unique_len;
- copy_to_user_ret((drm_unique_t *)arg, &u, sizeof(u), -EFAULT);
+ if (copy_to_user((drm_unique_t *)arg, &u, sizeof(u)))
+ return -EFAULT;
return 0;
}
@@ -72,15 +76,19 @@ int drm_setunique(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_unique_t u;
- if (dev->unique_len || dev->unique) return -EBUSY;
+ if (dev->unique_len || dev->unique)
+ return -EBUSY;
- copy_from_user_ret(&u, (drm_unique_t *)arg, sizeof(u), -EFAULT);
- if (!u.unique_len) return -EINVAL;
+ if (copy_from_user(&u, (drm_unique_t *)arg, sizeof(u)))
+ return -EFAULT;
+
+ if (!u.unique_len)
+ return -EINVAL;
dev->unique_len = u.unique_len;
dev->unique = drm_alloc(u.unique_len + 1, DRM_MEM_DRIVER);
- copy_from_user_ret(dev->unique, u.unique, dev->unique_len,
- -EFAULT);
+ if (copy_from_user(dev->unique, u.unique, dev->unique_len))
+ return -EFAULT;
dev->unique[dev->unique_len] = '\0';
dev->devname = drm_alloc(strlen(dev->name) + strlen(dev->unique) + 2,
diff --git a/drivers/char/drm/lists.c b/drivers/char/drm/lists.c
index 5da7cc6c5..60e66b8fb 100644
--- a/drivers/char/drm/lists.c
+++ b/drivers/char/drm/lists.c
@@ -34,7 +34,6 @@
int drm_waitlist_create(drm_waitlist_t *bl, int count)
{
- DRM_DEBUG("%d\n", count);
if (bl->count) return -EINVAL;
bl->count = count;
@@ -50,7 +49,6 @@ int drm_waitlist_create(drm_waitlist_t *bl, int count)
int drm_waitlist_destroy(drm_waitlist_t *bl)
{
- DRM_DEBUG("\n");
if (bl->rp != bl->wp) return -EINVAL;
if (bl->bufs) drm_free(bl->bufs,
(bl->count + 2) * sizeof(*bl->bufs),
@@ -69,8 +67,6 @@ int drm_waitlist_put(drm_waitlist_t *bl, drm_buf_t *buf)
unsigned long flags;
left = DRM_LEFTCOUNT(bl);
- DRM_DEBUG("put %d (%d left, rp = %p, wp = %p)\n",
- buf->idx, left, bl->rp, bl->wp);
if (!left) {
DRM_ERROR("Overflow while adding buffer %d from pid %d\n",
buf->idx, buf->pid);
@@ -103,13 +99,11 @@ drm_buf_t *drm_waitlist_get(drm_waitlist_t *bl)
if (++bl->rp >= bl->end) bl->rp = bl->bufs;
spin_unlock_irqrestore(&bl->read_lock, flags);
- DRM_DEBUG("get %d\n", buf->idx);
return buf;
}
int drm_freelist_create(drm_freelist_t *bl, int count)
{
- DRM_DEBUG("\n");
atomic_set(&bl->count, 0);
bl->next = NULL;
init_waitqueue_head(&bl->waiting);
@@ -123,7 +117,6 @@ int drm_freelist_create(drm_freelist_t *bl, int count)
int drm_freelist_destroy(drm_freelist_t *bl)
{
- DRM_DEBUG("\n");
atomic_set(&bl->count, 0);
bl->next = NULL;
return 0;
@@ -142,9 +135,6 @@ int drm_freelist_put(drm_device_t *dev, drm_freelist_t *bl, drm_buf_t *buf)
DRM_ERROR("Freed buffer %d: w%d, p%d, l%d\n",
buf->idx, buf->waiting, buf->pending, buf->list);
}
- DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n",
- buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh),
- buf->waiting, buf->pending);
if (!bl) return 1;
#if DRM_DMA_HISTOGRAM
buf->time_freed = get_cycles();
@@ -190,9 +180,6 @@ static drm_buf_t *drm_freelist_try(drm_freelist_t *bl)
atomic_dec(&bl->count);
buf->next = NULL;
buf->list = DRM_LIST_NONE;
- DRM_DEBUG("%d, count = %d, wfh = %d, w%d, p%d\n",
- buf->idx, atomic_read(&bl->count), atomic_read(&bl->wfh),
- buf->waiting, buf->pending);
if (buf->waiting || buf->pending) {
DRM_ERROR("Free buffer %d: w%d, p%d, l%d\n",
buf->idx, buf->waiting, buf->pending, buf->list);
@@ -212,13 +199,10 @@ drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block)
if (atomic_read(&bl->count) <= bl->low_mark) /* Became low */
atomic_set(&bl->wfh, 1);
if (atomic_read(&bl->wfh)) {
- DRM_DEBUG("Block = %d, count = %d, wfh = %d\n",
- block, atomic_read(&bl->count),
- atomic_read(&bl->wfh));
if (block) {
add_wait_queue(&bl->waiting, &entry);
- current->state = TASK_INTERRUPTIBLE;
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
if (!atomic_read(&bl->wfh)
&& (buf = drm_freelist_try(bl))) break;
schedule();
@@ -230,7 +214,5 @@ drm_buf_t *drm_freelist_get(drm_freelist_t *bl, int block)
return buf;
}
- DRM_DEBUG("Count = %d, wfh = %d\n",
- atomic_read(&bl->count), atomic_read(&bl->wfh));
return drm_freelist_try(bl);
}
diff --git a/drivers/char/drm/lock.c b/drivers/char/drm/lock.c
index 33b2cc03f..90d2f1300 100644
--- a/drivers/char/drm/lock.c
+++ b/drivers/char/drm/lock.c
@@ -50,7 +50,6 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
{
unsigned int old, new, prev;
- DRM_DEBUG("%d attempts\n", context);
do {
old = *lock;
if (old & _DRM_LOCK_HELD) new = old | _DRM_LOCK_CONT;
@@ -68,11 +67,8 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
}
if (new == (context | _DRM_LOCK_HELD)) {
/* Have lock */
- DRM_DEBUG("%d\n", context);
return 1;
}
- DRM_DEBUG("%d unable to get lock held by %d\n",
- context, _DRM_LOCKING_CONTEXT(old));
return 0;
}
@@ -89,7 +85,6 @@ int drm_lock_transfer(drm_device_t *dev,
new = context | _DRM_LOCK_HELD;
prev = cmpxchg(lock, old, new);
} while (prev != old);
- DRM_DEBUG("%d => %d\n", _DRM_LOCKING_CONTEXT(old), context);
return 1;
}
@@ -99,7 +94,6 @@ int drm_lock_free(drm_device_t *dev,
unsigned int old, new, prev;
pid_t pid = dev->lock.pid;
- DRM_DEBUG("%d\n", context);
dev->lock.pid = 0;
do {
old = *lock;
@@ -128,10 +122,10 @@ static int drm_flush_queue(drm_device_t *dev, int context)
atomic_inc(&q->use_count);
if (atomic_read(&q->use_count) > 1) {
atomic_inc(&q->block_write);
- current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&q->flush_queue, &entry);
atomic_inc(&q->block_count);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
if (!DRM_BUFCOUNT(&q->waitlist)) break;
schedule();
if (signal_pending(current)) {
@@ -218,7 +212,8 @@ int drm_finish(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_DEBUG("\n");
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
ret = drm_flush_block_and_flush(dev, lock.context, lock.flags);
drm_flush_unblock(dev, lock.context, lock.flags);
return ret;
diff --git a/drivers/char/drm/mga_bufs.c b/drivers/char/drm/mga_bufs.c
index b97eb4959..05d941b4c 100644
--- a/drivers/char/drm/mga_bufs.c
+++ b/drivers/char/drm/mga_bufs.c
@@ -57,16 +57,16 @@ int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
count = request.count;
order = drm_order(request.size);
size = 1 << order;
agp_offset = request.agp_start;
- alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size;
+ alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size;
page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
total = PAGE_SIZE << page_order;
byte_count = 0;
@@ -119,8 +119,6 @@ int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
buf->order = order;
buf->used = 0;
- DRM_DEBUG("offset : %ld\n", offset);
-
buf->offset = offset; /* Hrm */
buf->bus_address = dev->agp->base + agp_offset + offset;
buf->address = (void *)(agp_offset + offset + dev->agp->base);
@@ -130,7 +128,8 @@ int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
init_waitqueue_head(&buf->dma_wait);
buf->pid = 0;
- buf->dev_private = drm_alloc(sizeof(drm_mga_buf_priv_t), DRM_MEM_BUFS);
+ buf->dev_private = drm_alloc(sizeof(drm_mga_buf_priv_t),
+ DRM_MEM_BUFS);
buf->dev_priv_size = sizeof(drm_mga_buf_priv_t);
#if DRM_DMA_HISTOGRAM
@@ -142,9 +141,6 @@ int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
offset = offset + alignment;
entry->buf_count++;
byte_count += PAGE_SIZE << page_order;
-
- DRM_DEBUG("buffer %d @ %p\n",
- entry->buf_count, buf->address);
}
dma->buflist = drm_realloc(dma->buflist,
@@ -173,10 +169,10 @@ int mga_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
request.count = entry->buf_count;
request.size = size;
- copy_to_user_ret((drm_buf_desc_t *)arg,
+ if (copy_to_user((drm_buf_desc_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
atomic_dec(&dev->buf_alloc);
@@ -219,10 +215,10 @@ int mga_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
count = request.count;
order = drm_order(request.size);
@@ -234,7 +230,7 @@ int mga_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd,
if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
if (dev->queue_count) return -EBUSY; /* Not while in use */
- alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size) :size;
+ alignment = (request.flags & _DRM_PAGE_ALIGN) ? PAGE_ALIGN(size):size;
page_order = order - PAGE_SHIFT > 0 ? order - PAGE_SHIFT : 0;
total = PAGE_SIZE << page_order;
@@ -348,10 +344,10 @@ int mga_addbufs_pci(struct inode *inode, struct file *filp, unsigned int cmd,
request.count = entry->buf_count;
request.size = size;
- copy_to_user_ret((drm_buf_desc_t *)arg,
+ if (copy_to_user((drm_buf_desc_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
atomic_dec(&dev->buf_alloc);
return 0;
@@ -362,10 +358,10 @@ int mga_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
{
drm_buf_desc_t request;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
if(request.flags & _DRM_AGP_BUFFER)
return mga_addbufs_agp(inode, filp, cmd, arg);
@@ -393,58 +389,47 @@ int mga_infobufs(struct inode *inode, struct file *filp, unsigned int cmd,
++dev->buf_use; /* Can't allocate more after this call */
spin_unlock(&dev->count_lock);
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_info_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
if (dma->bufs[i].buf_count) ++count;
}
- DRM_DEBUG("count = %d\n", count);
-
if (request.count >= count) {
for (i = 0, count = 0; i < DRM_MAX_ORDER+1; i++) {
if (dma->bufs[i].buf_count) {
- copy_to_user_ret(&request.list[count].count,
+ if (copy_to_user(&request.list[count].count,
&dma->bufs[i].buf_count,
sizeof(dma->bufs[0]
- .buf_count),
- -EFAULT);
- copy_to_user_ret(&request.list[count].size,
+ .buf_count)) ||
+ copy_to_user(&request.list[count].size,
&dma->bufs[i].buf_size,
- sizeof(dma->bufs[0].buf_size),
- -EFAULT);
- copy_to_user_ret(&request.list[count].low_mark,
+ sizeof(dma->bufs[0].buf_size)) ||
+ copy_to_user(&request.list[count].low_mark,
&dma->bufs[i]
.freelist.low_mark,
sizeof(dma->bufs[0]
- .freelist.low_mark),
- -EFAULT);
- copy_to_user_ret(&request.list[count]
+ .freelist.low_mark)) ||
+ copy_to_user(&request.list[count]
.high_mark,
&dma->bufs[i]
.freelist.high_mark,
sizeof(dma->bufs[0]
- .freelist.high_mark),
- -EFAULT);
- DRM_DEBUG("%d %d %d %d %d\n",
- i,
- dma->bufs[i].buf_count,
- dma->bufs[i].buf_size,
- dma->bufs[i].freelist.low_mark,
- dma->bufs[i].freelist.high_mark);
+ .freelist.high_mark)))
+ return -EFAULT;
++count;
}
}
}
request.count = count;
- copy_to_user_ret((drm_buf_info_t *)arg,
+ if (copy_to_user((drm_buf_info_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
return 0;
}
@@ -461,13 +446,9 @@ int mga_markbufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
- (drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ if (copy_from_user(&request, (drm_buf_desc_t *)arg, sizeof(request)))
+ return -EFAULT;
- DRM_DEBUG("%d, %d, %d\n",
- request.size, request.low_mark, request.high_mark);
order = drm_order(request.size);
if (order < DRM_MIN_ORDER || order > DRM_MAX_ORDER) return -EINVAL;
entry = &dma->bufs[order];
@@ -496,17 +477,16 @@ int mga_freebufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_free_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
- DRM_DEBUG("%d\n", request.count);
for (i = 0; i < request.count; i++) {
- copy_from_user_ret(&idx,
+ if (copy_from_user(&idx,
&request.list[i],
- sizeof(idx),
- -EFAULT);
+ sizeof(idx)))
+ return -EFAULT;
if (idx < 0 || idx >= dma->buf_count) {
DRM_ERROR("Index %d (of %d max)\n",
idx, dma->buf_count - 1);
@@ -539,25 +519,19 @@ int mga_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- DRM_DEBUG("\n");
-
spin_lock(&dev->count_lock);
if (atomic_read(&dev->buf_alloc)) {
spin_unlock(&dev->count_lock);
- DRM_DEBUG("Busy\n");
return -EBUSY;
}
++dev->buf_use; /* Can't allocate more after this call */
spin_unlock(&dev->count_lock);
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_map_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
- DRM_DEBUG("mga_mapbufs\n");
- DRM_DEBUG("dma->flags : %x\n", dma->flags);
-
if (request.count >= dma->buf_count) {
if(dma->flags & _DRM_DMA_USE_AGP) {
drm_mga_private_t *dev_priv = dev->dev_private;
@@ -565,7 +539,6 @@ int mga_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
map = dev->maplist[dev_priv->buffer_map_idx];
if (!map) {
- DRM_DEBUG("map is null\n");
retcode = -EINVAL;
goto done;
}
@@ -628,10 +601,10 @@ int mga_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
request.count = dma->buf_count;
DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
- copy_to_user_ret((drm_buf_map_t *)arg,
+ if (copy_to_user((drm_buf_map_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
DRM_DEBUG("retcode : %d\n", retcode);
diff --git a/drivers/char/drm/mga_context.c b/drivers/char/drm/mga_context.c
index 9a73e6c14..b26c7c98e 100644
--- a/drivers/char/drm/mga_context.c
+++ b/drivers/char/drm/mga_context.c
@@ -35,9 +35,7 @@
static int mga_alloc_queue(drm_device_t *dev)
{
- int temp = drm_ctxbitmap_next(dev);
- DRM_DEBUG("mga_alloc_queue: %d\n", temp);
- return temp;
+ return drm_ctxbitmap_next(dev);
}
int mga_context_switch(drm_device_t *dev, int old, int new)
@@ -102,20 +100,21 @@ int mga_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
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 (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
+ return -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],
+ if (copy_to_user(&res.contexts[i],
&i,
- sizeof(i),
- -EFAULT);
+ sizeof(i)))
+ return -EFAULT;
}
}
res.count = DRM_RESERVED_CONTEXTS;
- copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+ if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
+ return -EFAULT;
return 0;
}
@@ -126,18 +125,18 @@ int mga_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
if ((ctx.handle = mga_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
/* Skip kernel's context and get a new one. */
ctx.handle = mga_alloc_queue(dev);
}
if (ctx.handle == -1) {
- DRM_DEBUG("Not enough free contexts.\n");
- /* Should this return -EBUSY instead? */
return -ENOMEM;
}
DRM_DEBUG("%d\n", ctx.handle);
- copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -153,10 +152,12 @@ int mga_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
{
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+ return -EFAULT;
/* This is 0, because we don't hanlde any context flags */
ctx.flags = 0;
- copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -167,7 +168,8 @@ int mga_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
return mga_context_switch(dev, dev->last_context, ctx.handle);
}
@@ -179,7 +181,8 @@ int mga_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
mga_context_switch_complete(dev, ctx.handle);
@@ -193,8 +196,11 @@ int mga_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
+ if(ctx.handle == DRM_KERNEL_CONTEXT+1) priv->remove_auth_on_close = 1;
+
if(ctx.handle != DRM_KERNEL_CONTEXT) {
drm_ctxbitmap_free(dev, ctx.handle);
}
diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c
index 0df0906e5..6adffb8a9 100644
--- a/drivers/char/drm/mga_dma.c
+++ b/drivers/char/drm/mga_dma.c
@@ -11,11 +11,11 @@
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
@@ -51,46 +51,29 @@ static int mga_flush_queue(drm_device_t *dev);
static unsigned long mga_alloc_page(drm_device_t *dev)
{
unsigned long address;
-
- DRM_DEBUG("%s\n", __FUNCTION__);
+
address = __get_free_page(GFP_KERNEL);
if(address == 0UL) {
return 0;
}
atomic_inc(&virt_to_page(address)->count);
- set_bit(PG_locked, &virt_to_page(address)->flags);
-
+ set_bit(PG_reserved, &virt_to_page(address)->flags);
+
return address;
}
static void mga_free_page(drm_device_t *dev, unsigned long page)
{
- DRM_DEBUG("%s\n", __FUNCTION__);
-
- if(page == 0UL) {
- return;
- }
+ if(!page) return;
atomic_dec(&virt_to_page(page)->count);
- clear_bit(PG_locked, &virt_to_page(page)->flags);
- wake_up(&virt_to_page(page)->wait);
+ clear_bit(PG_reserved, &virt_to_page(page)->flags);
free_page(page);
return;
}
static void mga_delay(void)
{
- return;
-}
-
-void mga_flush_write_combine(void)
-{
- int xchangeDummy;
- DRM_DEBUG("%s\n", __FUNCTION__);
-
- __asm__ volatile(" push %%eax ; xchg %%eax, %0 ; pop %%eax" : : "m" (xchangeDummy));
- __asm__ volatile(" push %%eax ; push %%ebx ; push %%ecx ; push %%edx ;"
- " movl $0,%%eax ; cpuid ; pop %%edx ; pop %%ecx ; pop %%ebx ;"
- " pop %%eax" : /* no outputs */ : /* no inputs */ );
+ return;
}
/* These are two age tags that will never be sent to
@@ -107,13 +90,11 @@ static int mga_freelist_init(drm_device_t *dev)
drm_mga_freelist_t *item;
int i;
- DRM_DEBUG("%s\n", __FUNCTION__);
-
dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
if(dev_priv->head == NULL) return -ENOMEM;
memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t));
dev_priv->head->age = MGA_BUF_USED;
-
+
for (i = 0; i < dma->buf_count; i++) {
buf = dma->buflist[ i ];
buf_priv = buf->dev_private;
@@ -133,7 +114,7 @@ static int mga_freelist_init(drm_device_t *dev)
buf_priv->dispatched = 0;
dev_priv->head->next = item;
}
-
+
return 0;
}
@@ -143,15 +124,13 @@ static void mga_freelist_cleanup(drm_device_t *dev)
drm_mga_freelist_t *item;
drm_mga_freelist_t *prev;
- DRM_DEBUG("%s\n", __FUNCTION__);
-
item = dev_priv->head;
while(item) {
prev = item;
item = item->next;
drm_free(prev, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
}
-
+
dev_priv->head = dev_priv->tail = NULL;
}
@@ -164,19 +143,21 @@ static inline void mga_dma_quiescent(drm_device_t *dev)
unsigned long end;
int i;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("dispatch_status = 0x%02x\n", dev_priv->dispatch_status);
end = jiffies + (HZ*3);
while(1) {
- if(!test_and_set_bit(MGA_IN_DISPATCH,
+ if(!test_and_set_bit(MGA_IN_DISPATCH,
&dev_priv->dispatch_status)) {
break;
}
if((signed)(end - jiffies) <= 0) {
- DRM_ERROR("irqs: %d wanted %d\n",
- atomic_read(&dev->total_irq),
+ DRM_ERROR("irqs: %d wanted %d\n",
+ atomic_read(&dev->total_irq),
atomic_read(&dma->total_lost));
- DRM_ERROR("lockup\n");
- goto out_nolock;
+ DRM_ERROR("lockup: dispatch_status = 0x%02x,"
+ " jiffies = %lu, end = %lu\n",
+ dev_priv->dispatch_status, jiffies, end);
+ return;
}
for (i = 0 ; i < 2000 ; i++) mga_delay();
}
@@ -184,19 +165,20 @@ static inline void mga_dma_quiescent(drm_device_t *dev)
DRM_DEBUG("quiescent status : %x\n", MGA_READ(MGAREG_STATUS));
while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) {
if((signed)(end - jiffies) <= 0) {
- DRM_ERROR("irqs: %d wanted %d\n",
- atomic_read(&dev->total_irq),
+ DRM_ERROR("irqs: %d wanted %d\n",
+ atomic_read(&dev->total_irq),
atomic_read(&dma->total_lost));
- DRM_ERROR("lockup\n");
- goto out_status;
+ DRM_ERROR("lockup\n");
+ clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status);
+ return;
}
- for (i = 0 ; i < 2000 ; i++) mga_delay();
+ for (i = 0 ; i < 2000 ; i++) mga_delay();
}
sarea_priv->dirty |= MGA_DMA_FLUSH;
-out_status:
clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status);
-out_nolock:
+ DRM_DEBUG("exit, dispatch_status = 0x%02x\n",
+ dev_priv->dispatch_status);
}
static void mga_reset_freelist(drm_device_t *dev)
@@ -214,44 +196,44 @@ static void mga_reset_freelist(drm_device_t *dev)
}
/* Least recently used :
- * These operations are not atomic b/c they are protected by the
+ * These operations are not atomic b/c they are protected by the
* hardware lock */
drm_buf_t *mga_freelist_get(drm_device_t *dev)
{
DECLARE_WAITQUEUE(entry, current);
- drm_mga_private_t *dev_priv =
+ drm_mga_private_t *dev_priv =
(drm_mga_private_t *) dev->dev_private;
drm_mga_freelist_t *prev;
drm_mga_freelist_t *next;
static int failed = 0;
+ int return_null = 0;
- DRM_DEBUG("%s : tail->age : %d last_prim_age : %d\n", __FUNCTION__,
- dev_priv->tail->age, dev_priv->last_prim_age);
-
if(failed >= 1000 && dev_priv->tail->age >= dev_priv->last_prim_age) {
- DRM_DEBUG("I'm waiting on the freelist!!! %d\n",
- dev_priv->last_prim_age);
- set_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status);
- current->state = TASK_INTERRUPTIBLE;
+ DRM_DEBUG("Waiting on freelist,"
+ " tail->age = %d, last_prim_age= %d\n",
+ dev_priv->tail->age,
+ dev_priv->last_prim_age);
add_wait_queue(&dev_priv->buf_queue, &entry);
+ set_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
mga_dma_schedule(dev, 0);
- if(!test_bit(MGA_IN_GETBUF,
- &dev_priv->dispatch_status))
+ if(dev_priv->tail->age < dev_priv->last_prim_age)
break;
atomic_inc(&dev->total_sleeps);
schedule();
if (signal_pending(current)) {
- clear_bit(MGA_IN_GETBUF,
- &dev_priv->dispatch_status);
- goto failed_getbuf;
+ ++return_null;
+ break;
}
}
- current->state = TASK_RUNNING;
+ clear_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status);
+ current->state = TASK_RUNNING;
remove_wait_queue(&dev_priv->buf_queue, &entry);
+ if (return_null) return NULL;
}
-
+
if(dev_priv->tail->age < dev_priv->last_prim_age) {
prev = dev_priv->tail->prev;
next = dev_priv->tail;
@@ -263,22 +245,19 @@ drm_buf_t *mga_freelist_get(drm_device_t *dev)
return next->buf;
}
-failed_getbuf:
failed++;
return NULL;
}
int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf)
{
- drm_mga_private_t *dev_priv =
+ drm_mga_private_t *dev_priv =
(drm_mga_private_t *) dev->dev_private;
drm_mga_buf_priv_t *buf_priv = buf->dev_private;
drm_mga_freelist_t *prev;
drm_mga_freelist_t *head;
drm_mga_freelist_t *next;
- DRM_DEBUG("%s\n", __FUNCTION__);
-
if(buf_priv->my_freelist->age == MGA_BUF_USED) {
/* Discarded buffer, put it on the tail */
next = buf_priv->my_freelist;
@@ -288,7 +267,6 @@ int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf)
next->prev = prev;
next->next = NULL;
dev_priv->tail = next;
- DRM_DEBUG("Discarded\n");
} else {
/* Normally aged buffer, put it on the head + 1,
* as the real head is a sentinal element
@@ -301,7 +279,7 @@ int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf)
next->prev = head;
next->next = prev;
}
-
+
return 0;
}
@@ -312,42 +290,41 @@ static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init)
int i, temp, size_of_buf;
int offset = init->reserved_map_agpstart;
- DRM_DEBUG("%s\n", __FUNCTION__);
- dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) /
+ dev_priv->primary_size = ((init->primary_size + PAGE_SIZE - 1) /
PAGE_SIZE) * PAGE_SIZE;
size_of_buf = dev_priv->primary_size / MGA_NUM_PRIM_BUFS;
dev_priv->warp_ucode_size = init->warp_ucode_size;
- dev_priv->prim_bufs = drm_alloc(sizeof(drm_mga_prim_buf_t *) *
- (MGA_NUM_PRIM_BUFS + 1),
+ dev_priv->prim_bufs = drm_alloc(sizeof(drm_mga_prim_buf_t *) *
+ (MGA_NUM_PRIM_BUFS + 1),
DRM_MEM_DRIVER);
if(dev_priv->prim_bufs == NULL) {
DRM_ERROR("Unable to allocate memory for prim_buf\n");
return -ENOMEM;
}
- memset(dev_priv->prim_bufs,
+ memset(dev_priv->prim_bufs,
0, sizeof(drm_mga_prim_buf_t *) * (MGA_NUM_PRIM_BUFS + 1));
-
+
temp = init->warp_ucode_size + dev_priv->primary_size;
temp = ((temp + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
-
- dev_priv->ioremap = drm_ioremap(dev->agp->base + offset,
+
+ dev_priv->ioremap = drm_ioremap(dev->agp->base + offset,
temp);
if(dev_priv->ioremap == NULL) {
- DRM_DEBUG("Ioremap failed\n");
+ DRM_ERROR("Ioremap failed\n");
return -ENOMEM;
}
init_waitqueue_head(&dev_priv->wait_queue);
-
+
for(i = 0; i < MGA_NUM_PRIM_BUFS; i++) {
- prim_buffer = drm_alloc(sizeof(drm_mga_prim_buf_t),
+ prim_buffer = drm_alloc(sizeof(drm_mga_prim_buf_t),
DRM_MEM_DRIVER);
if(prim_buffer == NULL) return -ENOMEM;
memset(prim_buffer, 0, sizeof(drm_mga_prim_buf_t));
prim_buffer->phys_head = offset + dev->agp->base;
- prim_buffer->current_dma_ptr =
- prim_buffer->head =
- (u32 *) (dev_priv->ioremap +
- offset -
+ prim_buffer->current_dma_ptr =
+ prim_buffer->head =
+ (u32 *) (dev_priv->ioremap +
+ offset -
init->reserved_map_agpstart);
prim_buffer->num_dwords = 0;
prim_buffer->max_dwords = size_of_buf / sizeof(u32);
@@ -359,11 +336,11 @@ static int mga_init_primary_bufs(drm_device_t *dev, drm_mga_init_t *init)
dev_priv->prim_bufs[i] = prim_buffer;
}
dev_priv->current_prim_idx = 0;
- dev_priv->next_prim =
- dev_priv->last_prim =
+ dev_priv->next_prim =
+ dev_priv->last_prim =
dev_priv->current_prim =
dev_priv->prim_bufs[0];
- dev_priv->next_prim_age = 2;
+ dev_priv->next_prim_age = 2;
dev_priv->last_prim_age = 1;
set_bit(MGA_BUF_IN_USE, &dev_priv->current_prim->buffer_status);
return 0;
@@ -380,13 +357,12 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim)
int next_idx;
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
dev_priv->last_prim = prim;
-
+
/* We never check for overflow, b/c there is always room */
PRIMPTR(prim);
if(num_dwords <= 0) {
- DRM_DEBUG("num_dwords == 0 when dispatched\n");
+ DRM_ERROR("num_dwords == 0 when dispatched\n");
goto out_prim_wait;
}
PRIMOUTREG( MGAREG_DMAPAD, 0);
@@ -397,32 +373,28 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim)
end = jiffies + (HZ*3);
if(sarea_priv->dirty & MGA_DMA_FLUSH) {
- DRM_DEBUG("Dma top flush\n");
while((MGA_READ(MGAREG_STATUS) & 0x00030001) != 0x00020000) {
if((signed)(end - jiffies) <= 0) {
- DRM_ERROR("irqs: %d wanted %d\n",
- atomic_read(&dev->total_irq),
+ DRM_ERROR("irqs: %d wanted %d\n",
+ atomic_read(&dev->total_irq),
atomic_read(&dma->total_lost));
- DRM_ERROR("lockup in fire primary "
- "(Dma Top Flush)\n");
+ DRM_ERROR("lockup (flush)\n");
goto out_prim_wait;
}
-
+
for (i = 0 ; i < 4096 ; i++) mga_delay();
}
sarea_priv->dirty &= ~(MGA_DMA_FLUSH);
} else {
- DRM_DEBUG("Status wait\n");
while((MGA_READ(MGAREG_STATUS) & 0x00020001) != 0x00020000) {
if((signed)(end - jiffies) <= 0) {
- DRM_ERROR("irqs: %d wanted %d\n",
- atomic_read(&dev->total_irq),
+ DRM_ERROR("irqs: %d wanted %d\n",
+ atomic_read(&dev->total_irq),
atomic_read(&dma->total_lost));
- DRM_ERROR("lockup in fire primary "
- "(Status Wait)\n");
+ DRM_ERROR("lockup (wait)\n");
goto out_prim_wait;
}
-
+
for (i = 0 ; i < 4096 ; i++) mga_delay();
}
}
@@ -433,9 +405,9 @@ void mga_fire_primary(drm_device_t *dev, drm_mga_prim_buf_t *prim)
MGA_WRITE(MGAREG_PRIMEND, (phys_head + num_dwords * 4) | use_agp);
prim->num_dwords = 0;
sarea_priv->last_enqueue = prim->prim_age;
-
+
next_idx = prim->idx + 1;
- if(next_idx >= MGA_NUM_PRIM_BUFS)
+ if(next_idx >= MGA_NUM_PRIM_BUFS)
next_idx = 0;
dev_priv->next_prim = dev_priv->prim_bufs[next_idx];
@@ -458,28 +430,26 @@ int mga_advance_primary(drm_device_t *dev)
drm_device_dma_t *dma = dev->dma;
int next_prim_idx;
int ret = 0;
-
+
/* This needs to reset the primary buffer if available,
* we should collect stats on how many times it bites
* it's tail */
- DRM_DEBUG("%s\n", __FUNCTION__);
-
+
next_prim_idx = dev_priv->current_prim_idx + 1;
if(next_prim_idx >= MGA_NUM_PRIM_BUFS)
next_prim_idx = 0;
prim_buffer = dev_priv->prim_bufs[next_prim_idx];
set_bit(MGA_IN_WAIT, &dev_priv->dispatch_status);
-
+
/* In use is cleared in interrupt handler */
-
+
if(test_and_set_bit(MGA_BUF_IN_USE, &prim_buffer->buffer_status)) {
add_wait_queue(&dev_priv->wait_queue, &entry);
- current->state = TASK_INTERRUPTIBLE;
-
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
mga_dma_schedule(dev, 0);
- if(!test_and_set_bit(MGA_BUF_IN_USE,
- &prim_buffer->buffer_status))
+ if(!test_and_set_bit(MGA_BUF_IN_USE,
+ &prim_buffer->buffer_status))
break;
atomic_inc(&dev->total_sleeps);
atomic_inc(&dma->total_missed_sched);
@@ -489,7 +459,7 @@ int mga_advance_primary(drm_device_t *dev)
break;
}
}
- current->state = TASK_RUNNING;
+ current->state = TASK_RUNNING;
remove_wait_queue(&dev_priv->wait_queue, &entry);
if(ret) return ret;
}
@@ -501,10 +471,10 @@ int mga_advance_primary(drm_device_t *dev)
prim_buffer->sec_used = 0;
prim_buffer->prim_age = dev_priv->next_prim_age++;
if(prim_buffer->prim_age == 0 || prim_buffer->prim_age == 0xffffffff) {
- mga_flush_queue(dev);
- mga_dma_quiescent(dev);
- mga_reset_freelist(dev);
- prim_buffer->prim_age = (dev_priv->next_prim_age += 2);
+ mga_flush_queue(dev);
+ mga_dma_quiescent(dev);
+ mga_reset_freelist(dev);
+ prim_buffer->prim_age = (dev_priv->next_prim_age += 2);
}
/* Reset all buffer status stuff */
@@ -521,88 +491,72 @@ int mga_advance_primary(drm_device_t *dev)
static inline int mga_decide_to_fire(drm_device_t *dev)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
-
- DRM_DEBUG("%s\n", __FUNCTION__);
if(test_bit(MGA_BUF_FORCE_FIRE, &dev_priv->next_prim->buffer_status)) {
- atomic_inc(&dma->total_prio);
return 1;
}
if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) &&
dev_priv->next_prim->num_dwords) {
- atomic_inc(&dma->total_prio);
return 1;
}
if (test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) &&
dev_priv->next_prim->num_dwords) {
- atomic_inc(&dma->total_prio);
return 1;
}
-
+
if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS - 1) {
- if(test_bit(MGA_BUF_SWAP_PENDING,
+ if(test_bit(MGA_BUF_SWAP_PENDING,
&dev_priv->next_prim->buffer_status)) {
- atomic_inc(&dma->total_dmas);
return 1;
}
}
if(atomic_read(&dev_priv->pending_bufs) <= MGA_NUM_PRIM_BUFS / 2) {
if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 8) {
- atomic_inc(&dma->total_hit);
return 1;
}
}
if(atomic_read(&dev_priv->pending_bufs) >= MGA_NUM_PRIM_BUFS / 2) {
if(dev_priv->next_prim->sec_used >= MGA_DMA_BUF_NR / 4) {
- atomic_inc(&dma->total_missed_free);
return 1;
}
}
- atomic_inc(&dma->total_tried);
return 0;
}
int mga_dma_schedule(drm_device_t *dev, int locked)
{
drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
- drm_device_dma_t *dma = dev->dma;
- int retval = 0;
+ int retval = 0;
- if (test_and_set_bit(0, &dev->dma_flag)) {
- atomic_inc(&dma->total_missed_dma);
+ if (!dev_priv) return -EBUSY;
+
+ if (test_and_set_bit(0, &dev->dma_flag)) {
retval = -EBUSY;
goto sch_out_wakeup;
}
-
- DRM_DEBUG("%s\n", __FUNCTION__);
- if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) ||
+ if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) ||
test_bit(MGA_IN_WAIT, &dev_priv->dispatch_status) ||
test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) {
locked = 1;
}
-
- if (!locked &&
+
+ if (!locked &&
!drm_lock_take(&dev->lock.hw_lock->lock, DRM_KERNEL_CONTEXT)) {
- atomic_inc(&dma->total_missed_lock);
clear_bit(0, &dev->dma_flag);
- DRM_DEBUG("Not locked\n");
retval = -EBUSY;
goto sch_out_wakeup;
}
- DRM_DEBUG("I'm locked\n");
if(!test_and_set_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status)) {
/* Fire dma buffer */
if(mga_decide_to_fire(dev)) {
- DRM_DEBUG("idx :%d\n", dev_priv->next_prim->idx);
- clear_bit(MGA_BUF_FORCE_FIRE,
+ clear_bit(MGA_BUF_FORCE_FIRE,
&dev_priv->next_prim->buffer_status);
if(dev_priv->current_prim == dev_priv->next_prim) {
/* Schedule overflow for a later time */
@@ -613,10 +567,8 @@ int mga_dma_schedule(drm_device_t *dev, int locked)
} else {
clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status);
}
- } else {
- DRM_DEBUG("I can't get the dispatch lock\n");
}
-
+
if (!locked) {
if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
DRM_KERNEL_CONTEXT)) {
@@ -624,6 +576,8 @@ int mga_dma_schedule(drm_device_t *dev, int locked)
}
}
+ clear_bit(0, &dev->dma_flag);
+
sch_out_wakeup:
if(test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status) &&
atomic_read(&dev_priv->pending_bufs) == 0) {
@@ -632,18 +586,10 @@ sch_out_wakeup:
wake_up_interruptible(&dev_priv->flush_queue);
}
- if(test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status) &&
- dev_priv->tail->age < dev_priv->last_prim_age) {
- clear_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status);
- DRM_DEBUG("Waking up buf queue\n");
+ if(test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)
+ && dev_priv->tail->age < dev_priv->last_prim_age)
wake_up_interruptible(&dev_priv->buf_queue);
- } else if (test_bit(MGA_IN_GETBUF, &dev_priv->dispatch_status)) {
- DRM_DEBUG("Not waking buf_queue on %d %d\n",
- atomic_read(&dev->total_irq),
- dev_priv->last_prim_age);
- }
- clear_bit(0, &dev->dma_flag);
return retval;
}
@@ -653,41 +599,40 @@ static void mga_dma_service(int irq, void *device, struct pt_regs *regs)
drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
drm_mga_prim_buf_t *last_prim_buffer;
- DRM_DEBUG("%s\n", __FUNCTION__);
atomic_inc(&dev->total_irq);
if((MGA_READ(MGAREG_STATUS) & 0x00000001) != 0x00000001) return;
MGA_WRITE(MGAREG_ICLEAR, 0x00000001);
last_prim_buffer = dev_priv->last_prim;
last_prim_buffer->num_dwords = 0;
last_prim_buffer->sec_used = 0;
- dev_priv->sarea_priv->last_dispatch =
+ dev_priv->sarea_priv->last_dispatch =
dev_priv->last_prim_age = last_prim_buffer->prim_age;
clear_bit(MGA_BUF_IN_USE, &last_prim_buffer->buffer_status);
- wake_up_interruptible(&dev_priv->wait_queue);
clear_bit(MGA_BUF_SWAP_PENDING, &last_prim_buffer->buffer_status);
clear_bit(MGA_IN_DISPATCH, &dev_priv->dispatch_status);
atomic_dec(&dev_priv->pending_bufs);
queue_task(&dev->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
+ wake_up_interruptible(&dev_priv->wait_queue);
}
static void mga_dma_task_queue(void *device)
{
- DRM_DEBUG("%s\n", __FUNCTION__);
mga_dma_schedule((drm_device_t *)device, 0);
}
int mga_dma_cleanup(drm_device_t *dev)
{
- DRM_DEBUG("%s\n", __FUNCTION__);
-
if(dev->dev_private) {
- drm_mga_private_t *dev_priv =
+ drm_mga_private_t *dev_priv =
(drm_mga_private_t *) dev->dev_private;
-
+
+ if (dev->irq) mga_flush_queue(dev);
+ mga_dma_quiescent(dev);
+
if(dev_priv->ioremap) {
- int temp = (dev_priv->warp_ucode_size +
- dev_priv->primary_size +
+ int temp = (dev_priv->warp_ucode_size +
+ dev_priv->primary_size +
PAGE_SIZE - 1) / PAGE_SIZE * PAGE_SIZE;
drm_ioremapfree((void *) dev_priv->ioremap, temp);
@@ -708,7 +653,7 @@ int mga_dma_cleanup(drm_device_t *dev)
}
}
drm_free(dev_priv->prim_bufs, sizeof(void *) *
- (MGA_NUM_PRIM_BUFS + 1),
+ (MGA_NUM_PRIM_BUFS + 1),
DRM_MEM_DRIVER);
}
if(dev_priv->head != NULL) {
@@ -716,7 +661,7 @@ int mga_dma_cleanup(drm_device_t *dev)
}
- drm_free(dev->dev_private, sizeof(drm_mga_private_t),
+ drm_free(dev->dev_private, sizeof(drm_mga_private_t),
DRM_MEM_DRIVER);
dev->dev_private = NULL;
}
@@ -727,9 +672,6 @@ int mga_dma_cleanup(drm_device_t *dev)
static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) {
drm_mga_private_t *dev_priv;
drm_map_t *sarea_map = NULL;
- int i;
-
- DRM_DEBUG("%s\n", __FUNCTION__);
dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
if(dev_priv == NULL) return -ENOMEM;
@@ -740,15 +682,14 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) {
if((init->reserved_map_idx >= dev->map_count) ||
(init->buffer_map_idx >= dev->map_count)) {
mga_dma_cleanup(dev);
- DRM_DEBUG("reserved_map or buffer_map are invalid\n");
return -EINVAL;
}
-
+
dev_priv->reserved_map_idx = init->reserved_map_idx;
dev_priv->buffer_map_idx = init->buffer_map_idx;
sarea_map = dev->maplist[0];
- dev_priv->sarea_priv = (drm_mga_sarea_t *)
- ((u8 *)sarea_map->handle +
+ dev_priv->sarea_priv = (drm_mga_sarea_t *)
+ ((u8 *)sarea_map->handle +
init->sarea_priv_offset);
/* Scale primary size to the next page */
@@ -766,23 +707,17 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) {
init_waitqueue_head(&dev_priv->flush_queue);
init_waitqueue_head(&dev_priv->buf_queue);
dev_priv->WarpPipe = 0xff000000;
+ dev_priv->vertexsize = 0;
- DRM_DEBUG("chipset: %d ucode_size: %d backOffset: %x depthOffset: %x\n",
- dev_priv->chipset, dev_priv->warp_ucode_size,
+ DRM_DEBUG("chipset=%d ucode_size=%d backOffset=%x depthOffset=%x\n",
+ dev_priv->chipset, dev_priv->warp_ucode_size,
dev_priv->backOffset, dev_priv->depthOffset);
DRM_DEBUG("cpp: %d sgram: %d stride: %d maccess: %x\n",
- dev_priv->cpp, dev_priv->sgram, dev_priv->stride,
+ dev_priv->cpp, dev_priv->sgram, dev_priv->stride,
dev_priv->mAccess);
-
- memcpy(&dev_priv->WarpIndex, &init->WarpIndex,
- sizeof(drm_mga_warp_index_t) * MGA_MAX_WARP_PIPES);
- for (i = 0 ; i < MGA_MAX_WARP_PIPES ; i++)
- DRM_DEBUG("warp pipe %d: installed: %d phys: %lx size: %x\n",
- i,
- dev_priv->WarpIndex[i].installed,
- dev_priv->WarpIndex[i].phys_addr,
- dev_priv->WarpIndex[i].size);
+ memcpy(&dev_priv->WarpIndex, &init->WarpIndex,
+ sizeof(drm_mga_warp_index_t) * MGA_MAX_WARP_PIPES);
if(mga_init_primary_bufs(dev, init) != 0) {
DRM_ERROR("Can not initialize primary buffers\n");
@@ -796,7 +731,7 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) {
return -ENOMEM;
}
- dev_priv->status_page =
+ dev_priv->status_page =
ioremap_nocache(virt_to_bus((void *)dev_priv->real_status_page),
PAGE_SIZE);
@@ -807,15 +742,15 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) {
}
/* Write status page when secend or softrap occurs */
- MGA_WRITE(MGAREG_PRIMPTR,
+ MGA_WRITE(MGAREG_PRIMPTR,
virt_to_bus((void *)dev_priv->real_status_page) | 0x00000003);
-
+
/* Private is now filled in, initialize the hardware */
{
PRIMLOCALS;
PRIMGETPTR( dev_priv );
-
+
PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_DWGSYNC, 0x0100);
@@ -823,13 +758,13 @@ static int mga_dma_initialize(drm_device_t *dev, drm_mga_init_t *init) {
/* Poll for the first buffer to insure that
* the status register will be correct
*/
-
+
mga_flush_write_combine();
MGA_WRITE(MGAREG_PRIMADDRESS, phys_head | TT_GENERAL);
- MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) |
+ MGA_WRITE(MGAREG_PRIMEND, ((phys_head + num_dwords * 4) |
PDEA_pagpxfer_enable));
-
+
while(MGA_READ(MGAREG_DWGSYNC) != 0x0100) ;
}
@@ -847,11 +782,10 @@ int mga_dma_init(struct inode *inode, struct file *filp,
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
drm_mga_init_t init;
-
- DRM_DEBUG("%s\n", __FUNCTION__);
- copy_from_user_ret(&init, (drm_mga_init_t *)arg, sizeof(init), -EFAULT);
-
+ if (copy_from_user(&init, (drm_mga_init_t *)arg, sizeof(init)))
+ return -EFAULT;
+
switch(init.func) {
case MGA_INIT_DMA:
return mga_dma_initialize(dev, &init);
@@ -867,7 +801,7 @@ int mga_irq_install(drm_device_t *dev, int irq)
int retcode;
if (!irq) return -EINVAL;
-
+
down(&dev->struct_sem);
if (dev->irq) {
up(&dev->struct_sem);
@@ -875,7 +809,7 @@ int mga_irq_install(drm_device_t *dev, int irq)
}
dev->irq = irq;
up(&dev->struct_sem);
-
+
DRM_DEBUG("install irq handler %d\n", irq);
dev->context_flag = 0;
@@ -916,7 +850,7 @@ int mga_irq_uninstall(drm_device_t *dev)
irq = dev->irq;
dev->irq = 0;
up(&dev->struct_sem);
-
+
if (!irq) return -EINVAL;
DRM_DEBUG("remove irq handler %d\n", irq);
MGA_WRITE(MGAREG_ICLEAR, 0x00000001);
@@ -931,10 +865,9 @@ int mga_control(struct inode *inode, struct file *filp, unsigned int cmd,
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->dev;
drm_control_t ctl;
-
- copy_from_user_ret(&ctl, (drm_control_t *)arg, sizeof(ctl), -EFAULT);
- DRM_DEBUG("%s\n", __FUNCTION__);
+ if (copy_from_user(&ctl, (drm_control_t *)arg, sizeof(ctl)))
+ return -EFAULT;
switch (ctl.func) {
case DRM_INST_HANDLER:
@@ -952,31 +885,29 @@ static int mga_flush_queue(drm_device_t *dev)
drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
int ret = 0;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ if(!dev_priv) return 0;
- if(dev_priv == NULL) {
- return 0;
- }
-
if(dev_priv->next_prim->num_dwords != 0) {
- current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&dev_priv->flush_queue, &entry);
+ if (test_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status))
+ DRM_ERROR("Incorrect mga_flush_queue logic\n");
set_bit(MGA_IN_FLUSH, &dev_priv->dispatch_status);
mga_dma_schedule(dev, 0);
for (;;) {
- if (!test_bit(MGA_IN_FLUSH,
- &dev_priv->dispatch_status))
+ current->state = TASK_INTERRUPTIBLE;
+ if (!test_bit(MGA_IN_FLUSH,
+ &dev_priv->dispatch_status))
break;
atomic_inc(&dev->total_sleeps);
schedule();
if (signal_pending(current)) {
ret = -EINTR; /* Can't restart */
- clear_bit(MGA_IN_FLUSH,
+ clear_bit(MGA_IN_FLUSH,
&dev_priv->dispatch_status);
break;
}
}
- current->state = TASK_RUNNING;
+ current->state = TASK_RUNNING;
remove_wait_queue(&dev_priv->flush_queue, &entry);
}
return ret;
@@ -992,18 +923,19 @@ void mga_reclaim_buffers(drm_device_t *dev, pid_t pid)
if(dev->dev_private == NULL) return;
if(dma->buflist == NULL) return;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("buf_count=%d\n", dma->buf_count);
+
mga_flush_queue(dev);
for (i = 0; i < dma->buf_count; i++) {
drm_buf_t *buf = dma->buflist[ i ];
drm_mga_buf_priv_t *buf_priv = buf->dev_private;
- /* Only buffers that need to get reclaimed ever
- * get set to free
+ /* Only buffers that need to get reclaimed ever
+ * get set to free
*/
if (buf->pid == pid && buf_priv) {
- if(buf_priv->my_freelist->age == MGA_BUF_USED)
+ if(buf_priv->my_freelist->age == MGA_BUF_USED)
buf_priv->my_freelist->age = MGA_BUF_FREE;
}
}
@@ -1018,29 +950,24 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd,
int ret = 0;
drm_lock_t lock;
- DRM_DEBUG("%s\n", __FUNCTION__);
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ 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);
- if (lock.context < 0) {
- return -EINVAL;
- }
-
+ if (lock.context < 0) return -EINVAL;
+
/* Only one queue:
*/
if (!ret) {
add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
if (!dev->lock.hw_lock) {
/* Device has been unregistered */
ret = -EINTR;
@@ -1053,10 +980,9 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd,
atomic_inc(&dev->total_locks);
break; /* Got lock */
}
-
+
/* Contention */
atomic_inc(&dev->total_sleeps);
- current->state = TASK_INTERRUPTIBLE;
schedule();
if (signal_pending(current)) {
ret = -ERESTARTSYS;
@@ -1066,20 +992,30 @@ int mga_lock(struct inode *inode, struct file *filp, unsigned int cmd,
current->state = TASK_RUNNING;
remove_wait_queue(&dev->lock.lock_queue, &entry);
}
-
+
if (!ret) {
+ sigemptyset(&dev->sigmask);
+ sigaddset(&dev->sigmask, SIGSTOP);
+ sigaddset(&dev->sigmask, SIGTSTP);
+ sigaddset(&dev->sigmask, SIGTTIN);
+ sigaddset(&dev->sigmask, SIGTTOU);
+ dev->sigdata.context = lock.context;
+ dev->sigdata.lock = dev->lock.hw_lock;
+ block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
+
if (lock.flags & _DRM_LOCK_QUIESCENT) {
DRM_DEBUG("_DRM_LOCK_QUIESCENT\n");
mga_flush_queue(dev);
mga_dma_quiescent(dev);
}
}
-
- DRM_DEBUG("%d %s\n", lock.context, ret ? "interrupted" : "has lock");
+
+ if (ret) DRM_DEBUG("%d %s\n", lock.context,
+ ret ? "interrupted" : "has lock");
return ret;
}
-
-int mga_flush_ioctl(struct inode *inode, struct file *filp,
+
+int mga_flush_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
drm_file_t *priv = filp->private_data;
@@ -1087,11 +1023,11 @@ int mga_flush_ioctl(struct inode *inode, struct file *filp,
drm_lock_t lock;
drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
- DRM_ERROR("mga_flush_ioctl called without lock held\n");
+ DRM_ERROR("lock not held\n");
return -EINVAL;
}
diff --git a/drivers/char/drm/mga_drm.h b/drivers/char/drm/mga_drm.h
index e75e91a4f..52cf77665 100644
--- a/drivers/char/drm/mga_drm.h
+++ b/drivers/char/drm/mga_drm.h
@@ -73,17 +73,19 @@
/* 3d state excluding texture units:
*/
-#define MGA_CTXREG_DSTORG 0 /* validated */
-#define MGA_CTXREG_MACCESS 1
-#define MGA_CTXREG_PLNWT 2
-#define MGA_CTXREG_DWGCTL 3
-#define MGA_CTXREG_ALPHACTRL 4
-#define MGA_CTXREG_FOGCOLOR 5
-#define MGA_CTXREG_WFLAG 6
-#define MGA_CTXREG_TDUAL0 7
-#define MGA_CTXREG_TDUAL1 8
-#define MGA_CTXREG_FCOL 9
-#define MGA_CTX_SETUP_SIZE 10
+#define MGA_CTXREG_DSTORG 0 /* validated */
+#define MGA_CTXREG_MACCESS 1
+#define MGA_CTXREG_PLNWT 2
+#define MGA_CTXREG_DWGCTL 3
+#define MGA_CTXREG_ALPHACTRL 4
+#define MGA_CTXREG_FOGCOLOR 5
+#define MGA_CTXREG_WFLAG 6
+#define MGA_CTXREG_TDUAL0 7
+#define MGA_CTXREG_TDUAL1 8
+#define MGA_CTXREG_FCOL 9
+#define MGA_CTXREG_STENCIL 10
+#define MGA_CTXREG_STENCILCTL 11
+#define MGA_CTX_SETUP_SIZE 12
/* 2d state
*/
@@ -233,6 +235,7 @@ typedef struct _drm_mga_sarea {
/* Mechanism to validate card state.
*/
int ctxOwner;
+ int vertexsize;
} drm_mga_sarea_t;
/* Device specific ioctls:
@@ -241,6 +244,8 @@ typedef struct _drm_mga_clear {
unsigned int clear_color;
unsigned int clear_depth;
unsigned int flags;
+ unsigned int clear_depth_mask;
+ unsigned int clear_color_mask;
} drm_mga_clear_t;
typedef struct _drm_mga_swap {
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
index acc42b833..4aaac6254 100644
--- a/drivers/char/drm/mga_drv.c
+++ b/drivers/char/drm/mga_drv.c
@@ -1,6 +1,6 @@
/* mga_drv.c -- Matrox g200/g400 driver -*- linux-c -*-
* Created: Mon Dec 13 01:56:22 1999 by jhartmann@precisioninsight.com
- *
+ *
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
* Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
* All Rights Reserved.
@@ -11,11 +11,11 @@
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
@@ -35,11 +35,11 @@
#include "mga_drv.h"
#define MGA_NAME "mga"
-#define MGA_DESC "Matrox g200/g400"
-#define MGA_DATE "20000719"
-#define MGA_MAJOR 1
+#define MGA_DESC "Matrox G200/G400"
+#define MGA_DATE "20000928"
+#define MGA_MAJOR 2
#define MGA_MINOR 0
-#define MGA_PATCHLEVEL 0
+#define MGA_PATCHLEVEL 1
static drm_device_t mga_device;
drm_ctx_t mga_res_ctx;
@@ -123,7 +123,7 @@ static char *mga = NULL;
#endif
MODULE_AUTHOR("VA Linux Systems, Inc.");
-MODULE_DESCRIPTION("Matrox g200/g400");
+MODULE_DESCRIPTION("Matrox G200/G400");
MODULE_PARM(mga, "s");
#ifndef MODULE
@@ -144,7 +144,7 @@ __setup("mga=", mga_options);
static int mga_setup(drm_device_t *dev)
{
int i;
-
+
atomic_set(&dev->ioctl_count, 0);
atomic_set(&dev->vma_count, 0);
dev->buf_use = 0;
@@ -187,22 +187,22 @@ static int mga_setup(drm_device_t *dev)
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);
-
+
DRM_DEBUG("\n");
-
+
/* The kernel's context could be created here, but is now created
in drm_dma_enqueue. This is more resource-efficient for
hardware that does not do DMA, but may mean that
drm_select_queue fails between the time the interrupt is
initialized and the time the queues are initialized. */
-
+
return 0;
}
@@ -216,16 +216,17 @@ static int mga_takedown(drm_device_t *dev)
DRM_DEBUG("\n");
+ if (dev->dev_private) mga_dma_cleanup(dev);
if (dev->irq) mga_irq_uninstall(dev);
-
+
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;
@@ -243,7 +244,7 @@ static int mga_takedown(drm_device_t *dev)
if (dev->agp) {
drm_agp_mem_t *entry;
drm_agp_mem_t *nexte;
-
+
/* Remove AGP resources, but leave dev->agp
intact until cleanup is called. */
for (entry = dev->agp->memory; entry; entry = nexte) {
@@ -253,10 +254,10 @@ static int mga_takedown(drm_device_t *dev)
drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
}
dev->agp->memory = NULL;
-
+
if (dev->agp->acquired && drm_agp.release)
(*drm_agp.release)();
-
+
dev->agp->acquired = 0;
dev->agp->enabled = 0;
}
@@ -268,7 +269,7 @@ static int mga_takedown(drm_device_t *dev)
}
dev->vmalist = NULL;
}
-
+
/* Clear map area and mtrr information */
if (dev->maplist) {
for (i = 0; i < dev->map_count; i++) {
@@ -304,7 +305,7 @@ static int mga_takedown(drm_device_t *dev)
dev->maplist = NULL;
dev->map_count = 0;
}
-
+
if (dev->queuelist) {
for (i = 0; i < dev->queue_count; i++) {
drm_waitlist_destroy(&dev->queuelist[i]->waitlist);
@@ -330,7 +331,7 @@ static int mga_takedown(drm_device_t *dev)
wake_up_interruptible(&dev->lock.lock_queue);
}
up(&dev->struct_sem);
-
+
return 0;
}
@@ -347,11 +348,10 @@ static int mga_init(void)
memset((void *)dev, 0, sizeof(*dev));
dev->count_lock = SPIN_LOCK_UNLOCKED;
sema_init(&dev->struct_sem, 1);
-
+
#ifdef MODULE
drm_parse_options(mga);
#endif
- DRM_DEBUG("doing misc_register\n");
if ((retcode = misc_register(&mga_misc))) {
DRM_ERROR("Cannot register \"%s\"\n", MGA_NAME);
return retcode;
@@ -359,11 +359,8 @@ static int mga_init(void)
dev->device = MKDEV(MISC_MAJOR, mga_misc.minor);
dev->name = MGA_NAME;
- DRM_DEBUG("doing mem init\n");
drm_mem_init();
- DRM_DEBUG("doing proc init\n");
drm_proc_init(dev);
- DRM_DEBUG("doing agp init\n");
dev->agp = drm_agp_init();
if(dev->agp == NULL) {
DRM_INFO("The mga drm module requires the agpgart module"
@@ -380,7 +377,6 @@ static int mga_init(void)
MTRR_TYPE_WRCOMB,
1);
#endif
- DRM_DEBUG("doing ctxbitmap init\n");
if((retcode = drm_ctxbitmap_init(dev))) {
DRM_ERROR("Cannot allocate memory for context bitmap.\n");
drm_proc_cleanup();
@@ -407,7 +403,7 @@ static void mga_cleanup(void)
drm_device_t *dev = &mga_device;
DRM_DEBUG("\n");
-
+
drm_proc_cleanup();
if (misc_deregister(&mga_misc)) {
DRM_ERROR("Cannot unload module\n");
@@ -415,11 +411,10 @@ static void mga_cleanup(void)
DRM_INFO("Module unloaded\n");
}
drm_ctxbitmap_cleanup(dev);
- mga_dma_cleanup(dev);
#ifdef CONFIG_MTRR
if(dev->agp && dev->agp->agp_mtrr) {
int retval;
- retval = mtrr_del(dev->agp->agp_mtrr,
+ retval = mtrr_del(dev->agp->agp_mtrr,
dev->agp->agp_info.aper_base,
dev->agp->agp_info.aper_size * 1024*1024);
DRM_DEBUG("mtrr_del = %d\n", retval);
@@ -444,17 +439,18 @@ int mga_version(struct inode *inode, struct file *filp, unsigned int cmd,
drm_version_t version;
int len;
- copy_from_user_ret(&version,
+ if (copy_from_user(&version,
(drm_version_t *)arg,
- sizeof(version),
- -EFAULT);
+ sizeof(version)))
+ return -EFAULT;
#define DRM_COPY(name,value) \
len = strlen(value); \
if (len > name##_len) len = name##_len; \
name##_len = strlen(value); \
if (len && name) { \
- copy_to_user_ret(name, value, len, -EFAULT); \
+ if (copy_to_user(name, value, len)) \
+ return -EFAULT; \
}
version.version_major = MGA_MAJOR;
@@ -465,10 +461,10 @@ int mga_version(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_COPY(version.date, MGA_DATE);
DRM_COPY(version.desc, MGA_DESC);
- copy_to_user_ret((drm_version_t *)arg,
+ if (copy_to_user((drm_version_t *)arg,
&version,
- sizeof(version),
- -EFAULT);
+ sizeof(version)))
+ return -EFAULT;
return 0;
}
@@ -476,7 +472,7 @@ int mga_open(struct inode *inode, struct file *filp)
{
drm_device_t *dev = &mga_device;
int retcode = 0;
-
+
DRM_DEBUG("open_count = %d\n", dev->open_count);
if (!(retcode = drm_open_helper(inode, filp, dev))) {
#if LINUX_VERSION_CODE < 0x020333
@@ -507,22 +503,27 @@ int mga_release(struct inode *inode, struct file *filp)
if (dev->lock.hw_lock && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)
&& dev->lock.pid == current->pid) {
mga_reclaim_buffers(dev, priv->pid);
- DRM_ERROR("Process %d dead, freeing lock for context %d\n",
- current->pid,
- _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
+ DRM_INFO("Process %d dead (ctx %d, d_s = 0x%02x)\n",
+ current->pid,
+ _DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock),
+ dev->dev_private ?
+ ((drm_mga_private_t *)dev->dev_private)
+ ->dispatch_status
+ : 0);
+
+ if (dev->dev_private)
+ ((drm_mga_private_t *)dev->dev_private)
+ ->dispatch_status &= MGA_IN_DISPATCH;
+
drm_lock_free(dev,
&dev->lock.hw_lock->lock,
_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock));
-
- /* FIXME: may require heavy-handed reset of
- hardware at this point, possibly
- processed via a callback to the X
- server. */
} else if (dev->lock.hw_lock) {
/* The lock is required to reclaim buffers */
DECLARE_WAITQUEUE(entry, current);
add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
if (!dev->lock.hw_lock) {
/* Device has been unregistered */
retcode = -EINTR;
@@ -534,10 +535,9 @@ int mga_release(struct inode *inode, struct file *filp)
dev->lock.lock_time = jiffies;
atomic_inc(&dev->total_locks);
break; /* Got lock */
- }
+ }
/* Contention */
atomic_inc(&dev->total_sleeps);
- current->state = TASK_INTERRUPTIBLE;
schedule();
if (signal_pending(current)) {
retcode = -ERESTARTSYS;
@@ -548,6 +548,9 @@ int mga_release(struct inode *inode, struct file *filp)
remove_wait_queue(&dev->lock.lock_queue, &entry);
if(!retcode) {
mga_reclaim_buffers(dev, priv->pid);
+ if (dev->dev_private)
+ ((drm_mga_private_t *)dev->dev_private)
+ ->dispatch_status &= MGA_IN_DISPATCH;
drm_lock_free(dev, &dev->lock.hw_lock->lock,
DRM_KERNEL_CONTEXT);
}
@@ -555,12 +558,19 @@ int mga_release(struct inode *inode, struct file *filp)
drm_fasync(-1, filp, 0);
down(&dev->struct_sem);
+ if (priv->remove_auth_on_close == 1) {
+ drm_file_t *temp = dev->file_first;
+ while(temp) {
+ temp->authenticated = 0;
+ temp = temp->next;
+ }
+ }
if (priv->prev) priv->prev->next = priv->next;
else dev->file_first = priv->next;
if (priv->next) priv->next->prev = priv->prev;
else dev->file_last = priv->prev;
up(&dev->struct_sem);
-
+
drm_free(priv, sizeof(*priv), DRM_MEM_FILES);
#if LINUX_VERSION_CODE < 0x020333
MOD_DEC_USE_COUNT; /* Needed before Linux 2.3.51 */
@@ -601,9 +611,6 @@ int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
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 >= MGA_IOCTL_COUNT) {
retcode = -EINVAL;
@@ -612,7 +619,10 @@ int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
func = ioctl->func;
if (!func) {
- DRM_DEBUG("no function\n");
+ DRM_DEBUG("no function: pid = %d, cmd = 0x%02x,"
+ " nr = 0x%02x, dev 0x%x, auth = %d\n",
+ current->pid, cmd, nr, dev->device,
+ priv->authenticated);
retcode = -EINVAL;
} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN))
|| (ioctl->auth_needed && !priv->authenticated)) {
@@ -621,7 +631,7 @@ int mga_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
retcode = (func)(inode, filp, cmd, arg);
}
}
-
+
atomic_dec(&dev->ioctl_count);
return retcode;
}
@@ -633,17 +643,15 @@ int mga_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_lock_t lock;
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
-
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ 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 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);
@@ -651,9 +659,8 @@ int mga_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
mga_dma_schedule(dev, 1);
if (drm_lock_free(dev, &dev->lock.hw_lock->lock,
- DRM_KERNEL_CONTEXT)) {
- DRM_ERROR("\n");
- }
+ DRM_KERNEL_CONTEXT)) DRM_ERROR("\n");
+ unblock_all_signals();
return 0;
}
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h
index fe9e3dbe9..e37cc2ef4 100644
--- a/drivers/char/drm/mga_drv.h
+++ b/drivers/char/drm/mga_drv.h
@@ -11,11 +11,11 @@
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
@@ -39,8 +39,8 @@
typedef struct {
u32 buffer_status;
- unsigned int num_dwords;
- unsigned int max_dwords;
+ int num_dwords;
+ int max_dwords;
u32 *current_dma_ptr;
u32 *head;
u32 phys_head;
@@ -50,7 +50,7 @@ typedef struct {
} drm_mga_prim_buf_t;
typedef struct _drm_mga_freelist {
- unsigned int age;
+ __volatile__ unsigned int age;
drm_buf_t *buf;
struct _drm_mga_freelist *next;
struct _drm_mga_freelist *prev;
@@ -82,6 +82,7 @@ typedef struct _drm_mga_private {
int use_agp;
drm_mga_warp_index_t WarpIndex[MGA_MAX_G400_PIPES];
unsigned int WarpPipe;
+ unsigned int vertexsize;
atomic_t pending_bufs;
void *status_page;
unsigned long real_status_page;
@@ -97,7 +98,7 @@ typedef struct _drm_mga_private {
wait_queue_head_t wait_queue; /* Processes waiting until interrupt */
wait_queue_head_t buf_queue; /* Processes waiting for a free buf */
/* Some validated register values:
- */
+ */
u32 mAccess;
} drm_mga_private_t;
@@ -128,7 +129,6 @@ extern int mga_dma_init(struct inode *inode, struct file *filp,
extern int mga_dma_cleanup(drm_device_t *dev);
extern int mga_flush_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern void mga_flush_write_combine(void);
extern unsigned int mga_create_sync_tag(drm_device_t *dev);
extern drm_buf_t *mga_freelist_get(drm_device_t *dev);
extern int mga_freelist_put(drm_device_t *dev, drm_buf_t *buf);
@@ -137,9 +137,9 @@ extern void mga_reclaim_buffers(drm_device_t *dev, pid_t pid);
/* mga_bufs.c */
-extern int mga_addbufs(struct inode *inode, struct file *filp,
+extern int mga_addbufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
-extern int mga_infobufs(struct inode *inode, struct file *filp,
+extern int mga_infobufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int mga_markbufs(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
@@ -179,6 +179,7 @@ extern int mga_rmctx(struct inode *inode, struct file *filp,
extern int mga_context_switch(drm_device_t *dev, int old, int new);
extern int mga_context_switch_complete(drm_device_t *dev, int new);
+#define mga_flush_write_combine() mb()
typedef enum {
TT_GENERAL,
@@ -201,7 +202,7 @@ typedef struct {
#define ISREG0(r) (r >= DWGREG0 && r <= DWGREG0_END)
#define ADRINDEX0(r) (u8)((r - DWGREG0) >> 2)
#define ADRINDEX1(r) (u8)(((r - DWGREG1) >> 2) | 0x80)
-#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r))
+#define ADRINDEX(r) (ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r))
#define MGA_VERBOSE 0
#define MGA_NUM_PRIM_BUFS 8
@@ -209,19 +210,26 @@ typedef struct {
#define PRIMLOCALS u8 tempIndex[4]; u32 *dma_ptr; u32 phys_head; \
int outcount, num_dwords
-#define PRIM_OVERFLOW(dev, dev_priv, length) do { \
- drm_mga_prim_buf_t *tmp_buf = \
- dev_priv->prim_bufs[dev_priv->current_prim_idx]; \
- if( test_bit(MGA_BUF_NEEDS_OVERFLOW, \
- &tmp_buf->buffer_status)) { \
- mga_advance_primary(dev); \
- mga_dma_schedule(dev, 1); \
- } else if( tmp_buf->max_dwords - tmp_buf->num_dwords < length ||\
- tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \
- set_bit(MGA_BUF_FORCE_FIRE, &tmp_buf->buffer_status); \
- mga_advance_primary(dev); \
- mga_dma_schedule(dev, 1); \
- } \
+#define PRIM_OVERFLOW(dev, dev_priv, length) do { \
+ drm_mga_prim_buf_t *tmp_buf = \
+ dev_priv->prim_bufs[dev_priv->current_prim_idx]; \
+ if( test_bit(MGA_BUF_NEEDS_OVERFLOW, &tmp_buf->buffer_status)) { \
+ mga_advance_primary(dev); \
+ mga_dma_schedule(dev, 1); \
+ tmp_buf = dev_priv->prim_bufs[dev_priv->current_prim_idx]; \
+ } else if( tmp_buf->max_dwords - tmp_buf->num_dwords < length || \
+ tmp_buf->sec_used > MGA_DMA_BUF_NR/2) { \
+ set_bit(MGA_BUF_FORCE_FIRE, &tmp_buf->buffer_status); \
+ mga_advance_primary(dev); \
+ mga_dma_schedule(dev, 1); \
+ tmp_buf = dev_priv->prim_bufs[dev_priv->current_prim_idx]; \
+ } \
+ if(MGA_VERBOSE) \
+ DRM_DEBUG("PRIMGETPTR in %s\n", __FUNCTION__); \
+ dma_ptr = tmp_buf->current_dma_ptr; \
+ num_dwords = tmp_buf->num_dwords; \
+ phys_head = tmp_buf->phys_head; \
+ outcount = 0; \
} while(0)
#define PRIMGETPTR(dev_priv) do { \
@@ -287,7 +295,7 @@ drm_mga_prim_buf_t *tmp_buf = \
num_dwords + 1 + outcount, ADRINDEX(reg), val); \
if( ++outcount == 4) { \
outcount = 0; \
- dma_ptr[0] = *(u32 *)tempIndex; \
+ dma_ptr[0] = *(unsigned long *)tempIndex; \
dma_ptr+=5; \
num_dwords += 5; \
} \
@@ -369,6 +377,72 @@ drm_mga_prim_buf_t *tmp_buf = \
#define MGAREG_YTOP 0x1c98
#define MGAREG_ZORG 0x1c0c
+/* Warp registers */
+#define MGAREG_WR0 0x2d00
+#define MGAREG_WR1 0x2d04
+#define MGAREG_WR2 0x2d08
+#define MGAREG_WR3 0x2d0c
+#define MGAREG_WR4 0x2d10
+#define MGAREG_WR5 0x2d14
+#define MGAREG_WR6 0x2d18
+#define MGAREG_WR7 0x2d1c
+#define MGAREG_WR8 0x2d20
+#define MGAREG_WR9 0x2d24
+#define MGAREG_WR10 0x2d28
+#define MGAREG_WR11 0x2d2c
+#define MGAREG_WR12 0x2d30
+#define MGAREG_WR13 0x2d34
+#define MGAREG_WR14 0x2d38
+#define MGAREG_WR15 0x2d3c
+#define MGAREG_WR16 0x2d40
+#define MGAREG_WR17 0x2d44
+#define MGAREG_WR18 0x2d48
+#define MGAREG_WR19 0x2d4c
+#define MGAREG_WR20 0x2d50
+#define MGAREG_WR21 0x2d54
+#define MGAREG_WR22 0x2d58
+#define MGAREG_WR23 0x2d5c
+#define MGAREG_WR24 0x2d60
+#define MGAREG_WR25 0x2d64
+#define MGAREG_WR26 0x2d68
+#define MGAREG_WR27 0x2d6c
+#define MGAREG_WR28 0x2d70
+#define MGAREG_WR29 0x2d74
+#define MGAREG_WR30 0x2d78
+#define MGAREG_WR31 0x2d7c
+#define MGAREG_WR32 0x2d80
+#define MGAREG_WR33 0x2d84
+#define MGAREG_WR34 0x2d88
+#define MGAREG_WR35 0x2d8c
+#define MGAREG_WR36 0x2d90
+#define MGAREG_WR37 0x2d94
+#define MGAREG_WR38 0x2d98
+#define MGAREG_WR39 0x2d9c
+#define MGAREG_WR40 0x2da0
+#define MGAREG_WR41 0x2da4
+#define MGAREG_WR42 0x2da8
+#define MGAREG_WR43 0x2dac
+#define MGAREG_WR44 0x2db0
+#define MGAREG_WR45 0x2db4
+#define MGAREG_WR46 0x2db8
+#define MGAREG_WR47 0x2dbc
+#define MGAREG_WR48 0x2dc0
+#define MGAREG_WR49 0x2dc4
+#define MGAREG_WR50 0x2dc8
+#define MGAREG_WR51 0x2dcc
+#define MGAREG_WR52 0x2dd0
+#define MGAREG_WR53 0x2dd4
+#define MGAREG_WR54 0x2dd8
+#define MGAREG_WR55 0x2ddc
+#define MGAREG_WR56 0x2de0
+#define MGAREG_WR57 0x2de4
+#define MGAREG_WR58 0x2de8
+#define MGAREG_WR59 0x2dec
+#define MGAREG_WR60 0x2df0
+#define MGAREG_WR61 0x2df4
+#define MGAREG_WR62 0x2df8
+#define MGAREG_WR63 0x2dfc
+
#define PDEA_pagpxfer_enable 0x2
#define WIA_wmode_suspend 0x0
@@ -388,8 +462,8 @@ drm_mga_prim_buf_t *tmp_buf = \
#define DC_atype_zi 0x30
#define DC_atype_blk 0x40
#define DC_atype_i 0x70
-#define DC_linear_xy 0x0
-#define DC_linear_linear 0x80
+#define DC_linear_xy 0x0
+#define DC_linear_linear 0x80
#define DC_zmode_nozcmp 0x0
#define DC_zmode_ze 0x200
#define DC_zmode_zne 0x300
@@ -397,16 +471,16 @@ drm_mga_prim_buf_t *tmp_buf = \
#define DC_zmode_zlte 0x500
#define DC_zmode_zgt 0x600
#define DC_zmode_zgte 0x700
-#define DC_solid_disable 0x0
-#define DC_solid_enable 0x800
-#define DC_arzero_disable 0x0
-#define DC_arzero_enable 0x1000
-#define DC_sgnzero_disable 0x0
-#define DC_sgnzero_enable 0x2000
-#define DC_shftzero_disable 0x0
-#define DC_shftzero_enable 0x4000
-#define DC_bop_SHIFT 16
-#define DC_trans_SHIFT 20
+#define DC_solid_disable 0x0
+#define DC_solid_enable 0x800
+#define DC_arzero_disable 0x0
+#define DC_arzero_enable 0x1000
+#define DC_sgnzero_disable 0x0
+#define DC_sgnzero_enable 0x2000
+#define DC_shftzero_disable 0x0
+#define DC_shftzero_enable 0x4000
+#define DC_bop_SHIFT 16
+#define DC_trans_SHIFT 20
#define DC_bltmod_bmonolef 0x0
#define DC_bltmod_bmonowf 0x8000000
#define DC_bltmod_bplan 0x2000000
@@ -415,21 +489,22 @@ drm_mga_prim_buf_t *tmp_buf = \
#define DC_bltmod_bu32rgb 0xe000000
#define DC_bltmod_bu24bgr 0x16000000
#define DC_bltmod_bu24rgb 0x1e000000
-#define DC_pattern_disable 0x0
-#define DC_pattern_enable 0x20000000
-#define DC_transc_disable 0x0
-#define DC_transc_enable 0x40000000
-#define DC_clipdis_disable 0x0
-#define DC_clipdis_enable 0x80000000
+#define DC_pattern_disable 0x0
+#define DC_pattern_enable 0x20000000
+#define DC_transc_disable 0x0
+#define DC_transc_enable 0x40000000
+#define DC_clipdis_disable 0x0
+#define DC_clipdis_enable 0x80000000
+
-#define SETADD_mode_vertlist 0x0
+#define SETADD_mode_vertlist 0x0
#define MGA_CLEAR_CMD (DC_opcod_trap | DC_arzero_enable | \
DC_sgnzero_enable | DC_shftzero_enable | \
(0xC << DC_bop_SHIFT) | DC_clipdis_enable | \
DC_solid_enable | DC_transc_enable)
-
+
#define MGA_COPY_CMD (DC_opcod_bitblt | DC_atype_rpl | DC_linear_xy | \
DC_solid_disable | DC_arzero_disable | \
diff --git a/drivers/char/drm/mga_state.c b/drivers/char/drm/mga_state.c
index 723ccc539..9bbd254c1 100644
--- a/drivers/char/drm/mga_state.c
+++ b/drivers/char/drm/mga_state.c
@@ -11,11 +11,11 @@
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
@@ -34,34 +34,50 @@
#include "mga_drv.h"
#include "drm.h"
+/* If you change the functions to set state, PLEASE
+ * change these values
+ */
+
+#define MGAEMITCLIP_SIZE 10
+#define MGAEMITCTX_SIZE 20
+#define MGAG200EMITTEX_SIZE 20
+#define MGAG400EMITTEX0_SIZE 30
+#define MGAG400EMITTEX1_SIZE 25
+#define MGAG400EMITPIPE_SIZE 50
+#define MGAG200EMITPIPE_SIZE 15
+
+#define MAX_STATE_SIZE ((MGAEMITCLIP_SIZE * MGA_NR_SAREA_CLIPRECTS) + \
+ MGAEMITCTX_SIZE + MGAG400EMITTEX0_SIZE + \
+ MGAG400EMITTEX1_SIZE + MGAG400EMITPIPE_SIZE)
+
static void mgaEmitClipRect(drm_mga_private_t * dev_priv,
drm_clip_rect_t * box)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int *regs = sarea_priv->ContextState;
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
/* This takes 10 dwords */
PRIMGETPTR(dev_priv);
- /* Force reset of dwgctl (eliminates clip disable) */
+ /* Force reset of dwgctl on G400 (eliminates clip disable bit) */
+ if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
#if 0
- PRIMOUTREG(MGAREG_DMAPAD, 0);
- PRIMOUTREG(MGAREG_DWGSYNC, 0);
- PRIMOUTREG(MGAREG_DWGSYNC, 0);
- PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
+ PRIMOUTREG(MGAREG_DMAPAD, 0);
+ PRIMOUTREG(MGAREG_DWGSYNC, 0);
+ PRIMOUTREG(MGAREG_DWGSYNC, 0);
+ PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
#else
- PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
- PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000);
- PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
- PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000);
+ PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
+ PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000);
+ PRIMOUTREG(MGAREG_DWGCTL, regs[MGA_CTXREG_DWGCTL]);
+ PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0x80000000);
#endif
-
+ }
PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_CXBNDRY, ((box->x2) << 16) | (box->x1));
- PRIMOUTREG(MGAREG_YTOP, box->y1 * dev_priv->stride / 2);
- PRIMOUTREG(MGAREG_YBOT, box->y2 * dev_priv->stride / 2);
+ PRIMOUTREG(MGAREG_YTOP, box->y1 * dev_priv->stride / dev_priv->cpp);
+ PRIMOUTREG(MGAREG_YBOT, box->y2 * dev_priv->stride / dev_priv->cpp);
PRIMADVANCE(dev_priv);
}
@@ -71,9 +87,8 @@ static void mgaEmitContext(drm_mga_private_t * dev_priv)
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int *regs = sarea_priv->ContextState;
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
- /* This takes a max of 15 dwords */
+ /* This takes a max of 20 dwords */
PRIMGETPTR(dev_priv);
PRIMOUTREG(MGAREG_DSTORG, regs[MGA_CTXREG_DSTORG]);
@@ -91,6 +106,11 @@ static void mgaEmitContext(drm_mga_private_t * dev_priv)
PRIMOUTREG(MGAREG_TDUALSTAGE0, regs[MGA_CTXREG_TDUAL0]);
PRIMOUTREG(MGAREG_TDUALSTAGE1, regs[MGA_CTXREG_TDUAL1]);
PRIMOUTREG(MGAREG_FCOL, regs[MGA_CTXREG_FCOL]);
+
+ PRIMOUTREG(MGAREG_STENCIL, regs[MGA_CTXREG_STENCIL]);
+ PRIMOUTREG(MGAREG_STENCILCTL, regs[MGA_CTXREG_STENCILCTL]);
+ PRIMOUTREG(MGAREG_DMAPAD, 0);
+ PRIMOUTREG(MGAREG_DMAPAD, 0);
} else {
PRIMOUTREG(MGAREG_FCOL, regs[MGA_CTXREG_FCOL]);
PRIMOUTREG(MGAREG_DMAPAD, 0);
@@ -106,7 +126,6 @@ static void mgaG200EmitTex(drm_mga_private_t * dev_priv)
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int *regs = sarea_priv->TexState[0];
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
PRIMGETPTR(dev_priv);
@@ -125,9 +144,9 @@ static void mgaG200EmitTex(drm_mga_private_t * dev_priv)
PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]);
PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]);
PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]);
- PRIMOUTREG(0x2d00 + 24 * 4, regs[MGA_TEXREG_WIDTH]);
+ PRIMOUTREG(MGAREG_WR24, regs[MGA_TEXREG_WIDTH]);
- PRIMOUTREG(0x2d00 + 34 * 4, regs[MGA_TEXREG_HEIGHT]);
+ PRIMOUTREG(MGAREG_WR34, regs[MGA_TEXREG_HEIGHT]);
PRIMOUTREG(MGAREG_TEXTRANS, 0xffff);
PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff);
PRIMOUTREG(MGAREG_DMAPAD, 0);
@@ -135,17 +154,17 @@ static void mgaG200EmitTex(drm_mga_private_t * dev_priv)
PRIMADVANCE(dev_priv);
}
+#define TMC_dualtex_enable 0x80
+
static void mgaG400EmitTex0(drm_mga_private_t * dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int *regs = sarea_priv->TexState[0];
- int multitex = sarea_priv->WarpPipe & MGA_T2;
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
PRIMGETPTR(dev_priv);
- /* This takes a max of 30 dwords */
+ /* This takes 30 dwords */
PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | 0x00008000);
PRIMOUTREG(MGAREG_TEXCTL, regs[MGA_TEXREG_CTL]);
@@ -160,22 +179,20 @@ static void mgaG400EmitTex0(drm_mga_private_t * dev_priv)
PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]);
PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]);
PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]);
- PRIMOUTREG(0x2d00 + 49 * 4, 0);
+ PRIMOUTREG(MGAREG_WR49, 0);
- PRIMOUTREG(0x2d00 + 57 * 4, 0);
- PRIMOUTREG(0x2d00 + 53 * 4, 0);
- PRIMOUTREG(0x2d00 + 61 * 4, 0);
- PRIMOUTREG(MGAREG_DMAPAD, 0);
+ PRIMOUTREG(MGAREG_WR57, 0);
+ PRIMOUTREG(MGAREG_WR53, 0);
+ PRIMOUTREG(MGAREG_WR61, 0);
+ PRIMOUTREG(MGAREG_WR52, 0x40);
- if (!multitex) {
- PRIMOUTREG(0x2d00 + 52 * 4, 0x40);
- PRIMOUTREG(0x2d00 + 60 * 4, 0x40);
- PRIMOUTREG(MGAREG_DMAPAD, 0);
- PRIMOUTREG(MGAREG_DMAPAD, 0);
- }
+ PRIMOUTREG(MGAREG_WR60, 0x40);
+ PRIMOUTREG(MGAREG_WR54, regs[MGA_TEXREG_WIDTH] | 0x40);
+ PRIMOUTREG(MGAREG_WR62, regs[MGA_TEXREG_HEIGHT] | 0x40);
+ PRIMOUTREG(MGAREG_DMAPAD, 0);
- PRIMOUTREG(0x2d00 + 54 * 4, regs[MGA_TEXREG_WIDTH] | 0x40);
- PRIMOUTREG(0x2d00 + 62 * 4, regs[MGA_TEXREG_HEIGHT] | 0x40);
+ PRIMOUTREG(MGAREG_DMAPAD, 0);
+ PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_TEXTRANS, 0xffff);
PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff);
@@ -189,7 +206,6 @@ static void mgaG400EmitTex1(drm_mga_private_t * dev_priv)
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int *regs = sarea_priv->TexState[1];
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
PRIMGETPTR(dev_priv);
@@ -209,14 +225,14 @@ static void mgaG400EmitTex1(drm_mga_private_t * dev_priv)
PRIMOUTREG(MGAREG_TEXORG4, regs[MGA_TEXREG_ORG4]);
PRIMOUTREG(MGAREG_TEXWIDTH, regs[MGA_TEXREG_WIDTH]);
PRIMOUTREG(MGAREG_TEXHEIGHT, regs[MGA_TEXREG_HEIGHT]);
- PRIMOUTREG(0x2d00 + 49 * 4, 0);
+ PRIMOUTREG(MGAREG_WR49, 0);
- PRIMOUTREG(0x2d00 + 57 * 4, 0);
- PRIMOUTREG(0x2d00 + 53 * 4, 0);
- PRIMOUTREG(0x2d00 + 61 * 4, 0);
- PRIMOUTREG(0x2d00 + 52 * 4, regs[MGA_TEXREG_WIDTH] | 0x40);
+ PRIMOUTREG(MGAREG_WR57, 0);
+ PRIMOUTREG(MGAREG_WR53, 0);
+ PRIMOUTREG(MGAREG_WR61, 0);
+ PRIMOUTREG(MGAREG_WR52, regs[MGA_TEXREG_WIDTH] | 0x40);
- PRIMOUTREG(0x2d00 + 60 * 4, regs[MGA_TEXREG_HEIGHT] | 0x40);
+ PRIMOUTREG(MGAREG_WR60, regs[MGA_TEXREG_HEIGHT] | 0x40);
PRIMOUTREG(MGAREG_TEXTRANS, 0xffff);
PRIMOUTREG(MGAREG_TEXTRANSHIGH, 0xffff);
PRIMOUTREG(MGAREG_TEXCTL2, regs[MGA_TEXREG_CTL2] | 0x00008000);
@@ -224,14 +240,16 @@ static void mgaG400EmitTex1(drm_mga_private_t * dev_priv)
PRIMADVANCE(dev_priv);
}
-#define EMIT_PIPE 50
+#define MAGIC_FPARAM_HEX_VALUE 0x46480000
+/* This is the hex value of 12800.0f which is a magic value we must
+ * set in wr56.
+ */
+
static void mgaG400EmitPipe(drm_mga_private_t * dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int pipe = sarea_priv->WarpPipe;
- float fParam = 12800.0f;
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
PRIMGETPTR(dev_priv);
@@ -263,14 +281,14 @@ static void mgaG400EmitPipe(drm_mga_private_t * dev_priv)
PRIMOUTREG(MGAREG_DWGCTL, MGA_FLUSH_CMD);
PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 1);
- PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_DWGSYNC, 0x7000);
- PRIMOUTREG(MGAREG_DMAPAD, 0);
-
- PRIMOUTREG(MGAREG_TEXCTL2, 0 | 0x00008000);
+ PRIMOUTREG(MGAREG_TEXCTL2, 0x00008000);
PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0);
+
PRIMOUTREG(MGAREG_TEXCTL2, 0x80 | 0x00008000);
PRIMOUTREG(MGAREG_LEN + MGAREG_MGA_EXEC, 0);
+ PRIMOUTREG(MGAREG_DMAPAD, 0);
+ PRIMOUTREG(MGAREG_DMAPAD, 0);
}
PRIMOUTREG(MGAREG_WVRTXSZ, 0x00001807);
@@ -286,18 +304,18 @@ static void mgaG400EmitPipe(drm_mga_private_t * dev_priv)
PRIMOUTREG(MGAREG_WFLAG, 0);
PRIMOUTREG(MGAREG_WFLAG1, 0);
- PRIMOUTREG(0x2d00 + 56 * 4, *((u32 *) (&fParam)));
+ PRIMOUTREG(MGAREG_WR56, MAGIC_FPARAM_HEX_VALUE);
PRIMOUTREG(MGAREG_DMAPAD, 0);
- PRIMOUTREG(0x2d00 + 49 * 4, 0); /* Tex stage 0 */
- PRIMOUTREG(0x2d00 + 57 * 4, 0); /* Tex stage 0 */
- PRIMOUTREG(0x2d00 + 53 * 4, 0); /* Tex stage 1 */
- PRIMOUTREG(0x2d00 + 61 * 4, 0); /* Tex stage 1 */
+ PRIMOUTREG(MGAREG_WR49, 0); /* Tex stage 0 */
+ PRIMOUTREG(MGAREG_WR57, 0); /* Tex stage 0 */
+ PRIMOUTREG(MGAREG_WR53, 0); /* Tex stage 1 */
+ PRIMOUTREG(MGAREG_WR61, 0); /* Tex stage 1 */
- PRIMOUTREG(0x2d00 + 54 * 4, 0x40); /* Tex stage 0 : w */
- PRIMOUTREG(0x2d00 + 62 * 4, 0x40); /* Tex stage 0 : h */
- PRIMOUTREG(0x2d00 + 52 * 4, 0x40); /* Tex stage 1 : w */
- PRIMOUTREG(0x2d00 + 60 * 4, 0x40); /* Tex stage 1 : h */
+ PRIMOUTREG(MGAREG_WR54, 0x40); /* Tex stage 0 : w */
+ PRIMOUTREG(MGAREG_WR62, 0x40); /* Tex stage 0 : h */
+ PRIMOUTREG(MGAREG_WR52, 0x40); /* Tex stage 1 : w */
+ PRIMOUTREG(MGAREG_WR60, 0x40); /* Tex stage 1 : h */
/* Dma pading required due to hw bug */
PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
@@ -314,7 +332,6 @@ static void mgaG200EmitPipe(drm_mga_private_t * dev_priv)
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int pipe = sarea_priv->WarpPipe;
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
PRIMGETPTR(dev_priv);
@@ -323,12 +340,12 @@ static void mgaG200EmitPipe(drm_mga_private_t * dev_priv)
PRIMOUTREG(MGAREG_WIADDR, WIA_wmode_suspend);
PRIMOUTREG(MGAREG_WVRTXSZ, 7);
PRIMOUTREG(MGAREG_WFLAG, 0);
- PRIMOUTREG(0x2d00 + 24 * 4, 0); /* tex w/h */
+ PRIMOUTREG(MGAREG_WR24, 0); /* tex w/h */
- PRIMOUTREG(0x2d00 + 25 * 4, 0x100);
- PRIMOUTREG(0x2d00 + 34 * 4, 0); /* tex w/h */
- PRIMOUTREG(0x2d00 + 42 * 4, 0xFFFF);
- PRIMOUTREG(0x2d00 + 60 * 4, 0xFFFF);
+ PRIMOUTREG(MGAREG_WR25, 0x100);
+ PRIMOUTREG(MGAREG_WR34, 0); /* tex w/h */
+ PRIMOUTREG(MGAREG_WR42, 0xFFFF);
+ PRIMOUTREG(MGAREG_WR60, 0xFFFF);
/* Dma pading required due to hw bug */
PRIMOUTREG(MGAREG_DMAPAD, 0xffffffff);
@@ -345,7 +362,6 @@ static void mgaEmitState(drm_mga_private_t * dev_priv)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int dirty = sarea_priv->dirty;
- DRM_DEBUG("%s\n", __FUNCTION__);
if (dev_priv->chipset == MGA_CARD_TYPE_G400) {
int multitex = sarea_priv->WarpPipe & MGA_T2;
@@ -387,7 +403,6 @@ static void mgaEmitState(drm_mga_private_t * dev_priv)
}
}
-
/* Disallow all write destinations except the front and backbuffer.
*/
static int mgaVerifyContext(drm_mga_private_t * dev_priv)
@@ -395,8 +410,6 @@ static int mgaVerifyContext(drm_mga_private_t * dev_priv)
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int *regs = sarea_priv->ContextState;
- DRM_DEBUG("%s\n", __FUNCTION__);
-
if (regs[MGA_CTXREG_DSTORG] != dev_priv->frontOffset &&
regs[MGA_CTXREG_DSTORG] != dev_priv->backOffset) {
DRM_DEBUG("BAD DSTORG: %x (front %x, back %x)\n\n",
@@ -415,8 +428,6 @@ static int mgaVerifyTex(drm_mga_private_t * dev_priv, int unit)
{
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- DRM_DEBUG("%s\n", __FUNCTION__);
-
if ((sarea_priv->TexState[unit][MGA_TEXREG_ORG] & 0x3) == 0x1) {
DRM_DEBUG("BAD TEXREG_ORG: %x, unit %d\n",
sarea_priv->TexState[unit][MGA_TEXREG_ORG],
@@ -434,8 +445,6 @@ static int mgaVerifyState(drm_mga_private_t * dev_priv)
unsigned int dirty = sarea_priv->dirty;
int rv = 0;
- DRM_DEBUG("%s\n", __FUNCTION__);
-
if (sarea_priv->nbox > MGA_NR_SAREA_CLIPRECTS)
sarea_priv->nbox = MGA_NR_SAREA_CLIPRECTS;
@@ -463,8 +472,6 @@ static int mgaVerifyIload(drm_mga_private_t * dev_priv,
unsigned long bus_address,
unsigned int dstOrg, int length)
{
- DRM_DEBUG("%s\n", __FUNCTION__);
-
if (dstOrg < dev_priv->textureOffset ||
dstOrg + length >
(dev_priv->textureOffset + dev_priv->textureSize)) {
@@ -487,16 +494,13 @@ static void mga_dma_dispatch_tex_blit(drm_device_t * dev,
int use_agp = PDEA_pagpxfer_enable | 0x00000001;
u16 y2;
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
y2 = length / 64;
PRIM_OVERFLOW(dev, dev_priv, 30);
- PRIMGETPTR(dev_priv);
PRIMOUTREG(MGAREG_DSTORG, destOrg);
PRIMOUTREG(MGAREG_MACCESS, 0x00000000);
- DRM_DEBUG("srcorg : %lx\n", bus_address | use_agp);
PRIMOUTREG(MGAREG_SRCORG, (u32) bus_address | use_agp);
PRIMOUTREG(MGAREG_AR5, 64);
@@ -510,10 +514,10 @@ static void mga_dma_dispatch_tex_blit(drm_device_t * dev,
PRIMOUTREG(MGAREG_FXBNDRY, (63 << 16));
PRIMOUTREG(MGAREG_YDSTLEN + MGAREG_MGA_EXEC, y2);
+ PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_SRCORG, 0);
PRIMOUTREG(MGAREG_PITCH, dev_priv->stride / dev_priv->cpp);
- PRIMOUTREG(MGAREG_DMAPAD, 0);
- PRIMOUTREG(MGAREG_DMAPAD, 0);
+ PRIMOUTREG(MGAREG_DWGSYNC, 0x7000);
PRIMADVANCE(dev_priv);
}
@@ -526,37 +530,23 @@ static void mga_dma_dispatch_vertex(drm_device_t * dev, drm_buf_t * buf)
int length = buf->used;
int use_agp = PDEA_pagpxfer_enable;
int i = 0;
- int primary_needed;
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
-
- DRM_DEBUG("dispatch vertex %d addr 0x%lx, "
- "length 0x%x nbox %d dirty %x\n",
- buf->idx, address, length,
- sarea_priv->nbox, sarea_priv->dirty);
-
- DRM_DEBUG("used : %d, total : %d\n", buf->used, buf->total);
if (buf->used) {
/* WARNING: if you change any of the state functions verify
- * these numbers (Overestimating this doesn't hurt).
+ * these numbers (Overestimating this doesn't hurt).
*/
buf_priv->dispatched = 1;
- primary_needed = (50 + 15 + 15 + 30 + 25 +
- 10 + 15 * MGA_NR_SAREA_CLIPRECTS);
- PRIM_OVERFLOW(dev, dev_priv, primary_needed);
+ PRIM_OVERFLOW(dev, dev_priv,
+ (MAX_STATE_SIZE + (5 * MGA_NR_SAREA_CLIPRECTS)));
mgaEmitState(dev_priv);
+
+#if 0
+ length = dev_priv->vertexsize * 3 * 4;
+#endif
+
do {
if (i < sarea_priv->nbox) {
- DRM_DEBUG("idx %d Emit box %d/%d:"
- "%d,%d - %d,%d\n",
- buf->idx,
- i, sarea_priv->nbox,
- sarea_priv->boxes[i].x1,
- sarea_priv->boxes[i].y1,
- sarea_priv->boxes[i].x2,
- sarea_priv->boxes[i].y2);
-
mgaEmitClipRect(dev_priv,
&sarea_priv->boxes[i]);
}
@@ -592,36 +582,19 @@ static void mga_dma_dispatch_indices(drm_device_t * dev,
unsigned int address = (unsigned int) buf->bus_address;
int use_agp = PDEA_pagpxfer_enable;
int i = 0;
- int primary_needed;
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
-
- DRM_DEBUG("dispatch indices %d addr 0x%x, "
- "start 0x%x end 0x%x nbox %d dirty %x\n",
- buf->idx, address, start, end,
- sarea_priv->nbox, sarea_priv->dirty);
if (start != end) {
/* WARNING: if you change any of the state functions verify
- * these numbers (Overestimating this doesn't hurt).
+ * these numbers (Overestimating this doesn't hurt).
*/
buf_priv->dispatched = 1;
- primary_needed = (50 + 15 + 15 + 30 + 25 +
- 10 + 15 * MGA_NR_SAREA_CLIPRECTS);
- PRIM_OVERFLOW(dev, dev_priv, primary_needed);
+ PRIM_OVERFLOW(dev, dev_priv,
+ (MAX_STATE_SIZE + (5 * MGA_NR_SAREA_CLIPRECTS)));
mgaEmitState(dev_priv);
do {
if (i < sarea_priv->nbox) {
- DRM_DEBUG("idx %d Emit box %d/%d:"
- "%d,%d - %d,%d\n",
- buf->idx,
- i, sarea_priv->nbox,
- sarea_priv->boxes[i].x1,
- sarea_priv->boxes[i].y1,
- sarea_priv->boxes[i].x2,
- sarea_priv->boxes[i].y2);
-
mgaEmitClipRect(dev_priv,
&sarea_priv->boxes[i]);
}
@@ -634,6 +607,7 @@ static void mga_dma_dispatch_indices(drm_device_t * dev,
SETADD_mode_vertlist));
PRIMOUTREG(MGAREG_SETUPEND,
((address + end) | use_agp));
+/* ((address + start + 12) | use_agp)); */
PRIMADVANCE(dev_priv);
} while (++i < sarea_priv->nbox);
}
@@ -648,7 +622,9 @@ static void mga_dma_dispatch_indices(drm_device_t * dev,
static void mga_dma_dispatch_clear(drm_device_t * dev, int flags,
unsigned int clear_color,
- unsigned int clear_zval)
+ unsigned int clear_zval,
+ unsigned int clear_colormask,
+ unsigned int clear_depthmask)
{
drm_mga_private_t *dev_priv = dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
@@ -657,32 +633,21 @@ static void mga_dma_dispatch_clear(drm_device_t * dev, int flags,
drm_clip_rect_t *pbox = sarea_priv->boxes;
unsigned int cmd;
int i;
- int primary_needed;
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
if (dev_priv->sgram)
cmd = MGA_CLEAR_CMD | DC_atype_blk;
else
cmd = MGA_CLEAR_CMD | DC_atype_rstr;
- primary_needed = nbox * 70;
- if (primary_needed == 0)
- primary_needed = 70;
- PRIM_OVERFLOW(dev, dev_priv, primary_needed);
- PRIMGETPTR(dev_priv);
+ PRIM_OVERFLOW(dev, dev_priv, 35 * MGA_NR_SAREA_CLIPRECTS);
for (i = 0; i < nbox; i++) {
unsigned int height = pbox[i].y2 - pbox[i].y1;
- DRM_DEBUG("dispatch clear %d,%d-%d,%d flags %x!\n",
- pbox[i].x1, pbox[i].y1, pbox[i].x2,
- pbox[i].y2, flags);
-
if (flags & MGA_FRONT) {
- DRM_DEBUG("clear front\n");
- PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_DMAPAD, 0);
+ PRIMOUTREG(MGAREG_PLNWT, clear_colormask);
PRIMOUTREG(MGAREG_YDSTLEN,
(pbox[i].y1 << 16) | height);
PRIMOUTREG(MGAREG_FXBNDRY,
@@ -695,9 +660,8 @@ static void mga_dma_dispatch_clear(drm_device_t * dev, int flags,
}
if (flags & MGA_BACK) {
- DRM_DEBUG("clear back\n");
- PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_DMAPAD, 0);
+ PRIMOUTREG(MGAREG_PLNWT, clear_colormask);
PRIMOUTREG(MGAREG_YDSTLEN,
(pbox[i].y1 << 16) | height);
PRIMOUTREG(MGAREG_FXBNDRY,
@@ -710,9 +674,8 @@ static void mga_dma_dispatch_clear(drm_device_t * dev, int flags,
}
if (flags & MGA_DEPTH) {
- DRM_DEBUG("clear depth\n");
- PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_DMAPAD, 0);
+ PRIMOUTREG(MGAREG_PLNWT, clear_depthmask);
PRIMOUTREG(MGAREG_YDSTLEN,
(pbox[i].y1 << 16) | height);
PRIMOUTREG(MGAREG_FXBNDRY,
@@ -741,14 +704,11 @@ static void mga_dma_dispatch_swap(drm_device_t * dev)
int nbox = sarea_priv->nbox;
drm_clip_rect_t *pbox = sarea_priv->boxes;
int i;
- int primary_needed;
+ int pixel_stride = dev_priv->stride / dev_priv->cpp;
+
PRIMLOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
- primary_needed = nbox * 5;
- primary_needed += 65;
- PRIM_OVERFLOW(dev, dev_priv, primary_needed);
- PRIMGETPTR(dev_priv);
+ PRIM_OVERFLOW(dev, dev_priv, (MGA_NR_SAREA_CLIPRECTS * 5) + 20);
PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_DMAPAD, 0);
@@ -758,7 +718,7 @@ static void mga_dma_dispatch_swap(drm_device_t * dev)
PRIMOUTREG(MGAREG_DSTORG, dev_priv->frontOffset);
PRIMOUTREG(MGAREG_MACCESS, dev_priv->mAccess);
PRIMOUTREG(MGAREG_SRCORG, dev_priv->backOffset);
- PRIMOUTREG(MGAREG_AR5, dev_priv->stride / 2);
+ PRIMOUTREG(MGAREG_AR5, pixel_stride);
PRIMOUTREG(MGAREG_DMAPAD, 0);
PRIMOUTREG(MGAREG_DMAPAD, 0);
@@ -767,10 +727,7 @@ static void mga_dma_dispatch_swap(drm_device_t * dev)
for (i = 0; i < nbox; i++) {
unsigned int h = pbox[i].y2 - pbox[i].y1;
- unsigned int start = pbox[i].y1 * dev_priv->stride / 2;
-
- DRM_DEBUG("dispatch swap %d,%d-%d,%d!\n",
- pbox[i].x1, pbox[i].y1, pbox[i].x2, pbox[i].y2);
+ unsigned int start = pbox[i].y1 * pixel_stride;
PRIMOUTREG(MGAREG_AR0, start + pbox[i].x2 - 1);
PRIMOUTREG(MGAREG_AR3, start + pbox[i].x1);
@@ -799,9 +756,8 @@ int mga_clear_bufs(struct inode *inode, struct file *filp,
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
drm_mga_clear_t clear;
- copy_from_user_ret(&clear, (drm_mga_clear_t *) arg, sizeof(clear),
- -EFAULT);
- DRM_DEBUG("%s\n", __FUNCTION__);
+ if (copy_from_user(&clear, (drm_mga_clear_t *) arg, sizeof(clear)))
+ return -EFAULT;
if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("mga_clear_bufs called without lock held\n");
@@ -815,7 +771,10 @@ int mga_clear_bufs(struct inode *inode, struct file *filp,
*/
dev_priv->sarea_priv->dirty |= MGA_UPLOAD_CTX;
mga_dma_dispatch_clear(dev, clear.flags,
- clear.clear_color, clear.clear_depth);
+ clear.clear_color,
+ clear.clear_depth,
+ clear.clear_color_mask,
+ clear.clear_depth_mask);
PRIMUPDATE(dev_priv);
mga_flush_write_combine();
mga_dma_schedule(dev, 1);
@@ -830,7 +789,6 @@ int mga_swap_bufs(struct inode *inode, struct file *filp,
drm_mga_private_t *dev_priv =
(drm_mga_private_t *) dev->dev_private;
drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
- DRM_DEBUG("%s\n", __FUNCTION__);
if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("mga_swap_bufs called without lock held\n");
@@ -865,11 +823,9 @@ int mga_iload(struct inode *inode, struct file *filp,
drm_mga_buf_priv_t *buf_priv;
drm_mga_iload_t iload;
unsigned long bus_address;
- DRM_DEBUG("%s\n", __FUNCTION__);
- DRM_DEBUG("Starting Iload\n");
- copy_from_user_ret(&iload, (drm_mga_iload_t *) arg, sizeof(iload),
- -EFAULT);
+ if (copy_from_user(&iload, (drm_mga_iload_t *) arg, sizeof(iload)))
+ return -EFAULT;
if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("mga_iload called without lock held\n");
@@ -879,8 +835,6 @@ int mga_iload(struct inode *inode, struct file *filp,
buf = dma->buflist[iload.idx];
buf_priv = buf->dev_private;
bus_address = buf->bus_address;
- DRM_DEBUG("bus_address %lx, length %d, destorg : %x\n",
- bus_address, iload.length, iload.destOrg);
if (mgaVerifyIload(dev_priv,
bus_address, iload.destOrg, iload.length)) {
@@ -911,18 +865,15 @@ int mga_vertex(struct inode *inode, struct file *filp,
drm_buf_t *buf;
drm_mga_buf_priv_t *buf_priv;
drm_mga_vertex_t vertex;
- DRM_DEBUG("%s\n", __FUNCTION__);
- copy_from_user_ret(&vertex, (drm_mga_vertex_t *) arg,
- sizeof(vertex), -EFAULT);
+ if (copy_from_user(&vertex, (drm_mga_vertex_t *) arg, sizeof(vertex)))
+ return -EFAULT;
if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("mga_vertex called without lock held\n");
return -EINVAL;
}
- DRM_DEBUG("mga_vertex\n");
-
buf = dma->buflist[vertex.idx];
buf_priv = buf->dev_private;
@@ -936,7 +887,6 @@ int mga_vertex(struct inode *inode, struct file *filp,
buf_priv->dispatched = 0;
mga_freelist_put(dev, buf);
}
- DRM_DEBUG("bad state\n");
return -EINVAL;
}
@@ -960,18 +910,16 @@ int mga_indices(struct inode *inode, struct file *filp,
drm_buf_t *buf;
drm_mga_buf_priv_t *buf_priv;
drm_mga_indices_t indices;
- DRM_DEBUG("%s\n", __FUNCTION__);
- copy_from_user_ret(&indices, (drm_mga_indices_t *) arg,
- sizeof(indices), -EFAULT);
+ if (copy_from_user(&indices,
+ (drm_mga_indices_t *)arg, sizeof(indices)))
+ return -EFAULT;
if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("mga_indices called without lock held\n");
return -EINVAL;
}
- DRM_DEBUG("mga_indices\n");
-
buf = dma->buflist[indices.idx];
buf_priv = buf->dev_private;
@@ -1001,17 +949,18 @@ static int mga_dma_get_buffers(drm_device_t * dev, drm_dma_t * d)
{
int i;
drm_buf_t *buf;
- DRM_DEBUG("%s\n", __FUNCTION__);
for (i = d->granted_count; i < d->request_count; i++) {
buf = mga_freelist_get(dev);
if (!buf)
break;
buf->pid = current->pid;
- copy_to_user_ret(&d->request_indices[i],
- &buf->idx, sizeof(buf->idx), -EFAULT);
- copy_to_user_ret(&d->request_sizes[i],
- &buf->total, sizeof(buf->total), -EFAULT);
+ if (copy_to_user(&d->request_indices[i],
+ &buf->idx, sizeof(buf->idx)))
+ return -EFAULT;
+ if (copy_to_user(&d->request_sizes[i],
+ &buf->total, sizeof(buf->total)))
+ return -EFAULT;
++d->granted_count;
}
return 0;
@@ -1025,11 +974,9 @@ int mga_dma(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_dma_t *dma = dev->dma;
int retcode = 0;
drm_dma_t d;
- DRM_DEBUG("%s\n", __FUNCTION__);
- copy_from_user_ret(&d, (drm_dma_t *) arg, sizeof(d), -EFAULT);
- DRM_DEBUG("%d %d: %d send, %d req\n",
- current->pid, d.context, d.send_count, d.request_count);
+ if (copy_from_user(&d, (drm_dma_t *) arg, sizeof(d)))
+ return -EFAULT;
if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
DRM_ERROR("mga_dma called without lock held\n");
@@ -1060,8 +1007,7 @@ int mga_dma(struct inode *inode, struct file *filp, unsigned int cmd,
retcode = mga_dma_get_buffers(dev, &d);
}
- DRM_DEBUG("%d returning, granted = %d\n",
- current->pid, d.granted_count);
- copy_to_user_ret((drm_dma_t *) arg, &d, sizeof(d), -EFAULT);
+ if (copy_to_user((drm_dma_t *) arg, &d, sizeof(d)))
+ return -EFAULT;
return retcode;
}
diff --git a/drivers/char/drm/r128_bufs.c b/drivers/char/drm/r128_bufs.c
index bd81dcdc0..7e76441ee 100644
--- a/drivers/char/drm/r128_bufs.c
+++ b/drivers/char/drm/r128_bufs.c
@@ -60,10 +60,10 @@ int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dma) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
count = request.count;
order = drm_order(request.size);
@@ -173,10 +173,10 @@ int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd,
request.count = entry->buf_count;
request.size = size;
- copy_to_user_ret((drm_buf_desc_t *)arg,
+ if (copy_to_user((drm_buf_desc_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
dma->flags = _DRM_DMA_USE_AGP;
@@ -195,10 +195,10 @@ int r128_addbufs(struct inode *inode, struct file *filp, unsigned int cmd,
if (!dev_priv || dev_priv->is_pci) return -EINVAL;
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_desc_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
#if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE)
if (request.flags & _DRM_AGP_BUFFER)
@@ -234,10 +234,10 @@ int r128_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
++dev->buf_use; /* Can't allocate more after this call */
spin_unlock(&dev->count_lock);
- copy_from_user_ret(&request,
+ if (copy_from_user(&request,
(drm_buf_map_t *)arg,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
if (request.count >= dma->buf_count) {
if (dma->flags & _DRM_DMA_USE_AGP) {
@@ -300,10 +300,10 @@ int r128_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd,
request.count = dma->buf_count;
DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode);
- copy_to_user_ret((drm_buf_map_t *)arg,
+ if (copy_to_user((drm_buf_map_t *)arg,
&request,
- sizeof(request),
- -EFAULT);
+ sizeof(request)))
+ return -EFAULT;
return retcode;
}
diff --git a/drivers/char/drm/r128_context.c b/drivers/char/drm/r128_context.c
index 2dd716d4b..9cadadbaf 100644
--- a/drivers/char/drm/r128_context.c
+++ b/drivers/char/drm/r128_context.c
@@ -103,19 +103,21 @@ int r128_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
int i;
DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
- copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+ if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
+ return -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],
+ if (copy_to_user(&res.contexts[i],
&i,
- sizeof(i),
- -EFAULT);
+ sizeof(i)))
+ return -EFAULT;
}
}
res.count = DRM_RESERVED_CONTEXTS;
- copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+ if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
+ return -EFAULT;
return 0;
}
@@ -127,7 +129,8 @@ int r128_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
if ((ctx.handle = r128_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
/* Skip kernel's context and get a new one. */
ctx.handle = r128_alloc_queue(dev);
@@ -139,7 +142,8 @@ int r128_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
return -ENOMEM;
}
- copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -148,7 +152,8 @@ int r128_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
{
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+ return -EFAULT;
if (ctx.flags==_DRM_CONTEXT_PRESERVED)
r128_res_ctx.handle=ctx.handle;
return 0;
@@ -159,10 +164,12 @@ int r128_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
{
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+ return -EFAULT;
/* This is 0, because we don't hanlde any context flags */
ctx.flags = 0;
- copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -173,7 +180,8 @@ int r128_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
return r128_context_switch(dev, dev->last_context, ctx.handle);
}
@@ -185,7 +193,8 @@ int r128_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
r128_context_switch_complete(dev, ctx.handle);
@@ -199,7 +208,8 @@ int r128_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
drm_ctxbitmap_free(dev, ctx.handle);
diff --git a/drivers/char/drm/r128_dma.c b/drivers/char/drm/r128_dma.c
index 16f79c1f6..bcba67826 100644
--- a/drivers/char/drm/r128_dma.c
+++ b/drivers/char/drm/r128_dma.c
@@ -68,24 +68,8 @@ int R128_READ_PLL(drm_device_t *dev, int addr)
return R128_READ(R128_CLOCK_CNTL_DATA);
}
-static void r128_flush_write_combine(void)
-{
- int xchangeDummy;
-
- __asm__ volatile("push %%eax ;"
- "xchg %%eax, %0 ;"
- "pop %%eax" : : "m" (xchangeDummy));
- __asm__ volatile("push %%eax ;"
- "push %%ebx ;"
- "push %%ecx ;"
- "push %%edx ;"
- "movl $0,%%eax ;"
- "cpuid ;"
- "pop %%edx ;"
- "pop %%ecx ;"
- "pop %%ebx ;"
- "pop %%eax" : /* no outputs */ : /* no inputs */ );
-}
+#define r128_flush_write_combine() mb()
+
static void r128_status(drm_device_t *dev)
{
@@ -211,8 +195,8 @@ int r128_init_cce(struct inode *inode, struct file *filp,
drm_device_t *dev = priv->dev;
drm_r128_init_t init;
- copy_from_user_ret(&init, (drm_r128_init_t *)arg, sizeof(init),
- -EFAULT);
+ if (copy_from_user(&init, (drm_r128_init_t *)arg, sizeof(init)))
+ return -EFAULT;
switch (init.func) {
case R128_INIT_CCE:
@@ -680,8 +664,8 @@ int r128_submit_pkt(struct inode *inode, struct file *filp,
return -EINVAL;
}
- copy_from_user_ret(&packet, (drm_r128_packet_t *)arg, sizeof(packet),
- -EFAULT);
+ if (copy_from_user(&packet, (drm_r128_packet_t *)arg, sizeof(packet)))
+ return -EFAULT;
c = packet.count;
size = c * sizeof(*buffer);
@@ -696,7 +680,8 @@ int r128_submit_pkt(struct inode *inode, struct file *filp,
}
if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM;
- copy_from_user_ret(buffer, packet.buffer, size, -EFAULT);
+ if (copy_from_user(buffer, packet.buffer, size))
+ return -EFAULT;
if (dev_priv->cce_secure)
ret = r128_submit_packets_ring_secure(dev, buffer, &c);
@@ -706,7 +691,8 @@ int r128_submit_pkt(struct inode *inode, struct file *filp,
c += left;
} else {
if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM;
- copy_from_user_ret(buffer, packet.buffer, size, -EFAULT);
+ if (copy_from_user(buffer, packet.buffer, size))
+ return -EFAULT;
if (dev_priv->cce_secure)
ret = r128_submit_packets_pio_secure(dev, buffer, &c);
@@ -717,8 +703,8 @@ int r128_submit_pkt(struct inode *inode, struct file *filp,
kfree(buffer);
packet.count = c;
- copy_to_user_ret((drm_r128_packet_t *)arg, &packet, sizeof(packet),
- -EFAULT);
+ if (copy_to_user((drm_r128_packet_t *)arg, &packet, sizeof(packet)))
+ return -EFAULT;
if (ret) return ret;
else if (c > 0) return -EAGAIN;
@@ -855,14 +841,13 @@ static int r128_get_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v)
buf = r128_freelist_get(dev);
if (!buf) break;
buf->pid = current->pid;
- copy_to_user_ret(&v->request_indices[i],
+ if (copy_to_user(&v->request_indices[i],
&buf->idx,
- sizeof(buf->idx),
- -EFAULT);
- copy_to_user_ret(&v->request_sizes[i],
+ sizeof(buf->idx)) ||
+ copy_to_user(&v->request_sizes[i],
&buf->total,
- sizeof(buf->total),
- -EFAULT);
+ sizeof(buf->total)))
+ return -EFAULT;
++v->granted_count;
}
return 0;
@@ -889,7 +874,8 @@ int r128_vertex_buf(struct inode *inode, struct file *filp, unsigned int cmd,
return -EINVAL;
}
- copy_from_user_ret(&v, (drm_r128_vertex_t *)arg, sizeof(v), -EFAULT);
+ if (copy_from_user(&v, (drm_r128_vertex_t *)arg, sizeof(v)))
+ return -EFAULT;
DRM_DEBUG("%d: %d send, %d req\n",
current->pid, v.send_count, v.request_count);
@@ -916,7 +902,8 @@ int r128_vertex_buf(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_DEBUG("%d returning, granted = %d\n",
current->pid, v.granted_count);
- copy_to_user_ret((drm_r128_vertex_t *)arg, &v, sizeof(v), -EFAULT);
+ if (copy_to_user((drm_r128_vertex_t *)arg, &v, sizeof(v)))
+ return -EFAULT;
return retcode;
}
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c
index e0080e595..7ae498014 100644
--- a/drivers/char/drm/r128_drv.c
+++ b/drivers/char/drm/r128_drv.c
@@ -35,7 +35,7 @@
#define R128_NAME "r128"
#define R128_DESC "ATI Rage 128"
-#define R128_DATE "20000719"
+#define R128_DATE "20000928"
#define R128_MAJOR 1
#define R128_MINOR 0
#define R128_PATCHLEVEL 0
@@ -420,17 +420,18 @@ int r128_version(struct inode *inode, struct file *filp, unsigned int cmd,
drm_version_t version;
int len;
- copy_from_user_ret(&version,
+ if (copy_from_user(&version,
(drm_version_t *)arg,
- sizeof(version),
- -EFAULT);
+ sizeof(version)))
+ return -EFAULT;
#define DRM_COPY(name,value) \
len = strlen(value); \
if (len > name##_len) len = name##_len; \
name##_len = strlen(value); \
if (len && name) { \
- copy_to_user_ret(name, value, len, -EFAULT); \
+ if (copy_to_user(name, value, len)) \
+ return -EFAULT; \
}
version.version_major = R128_MAJOR;
@@ -441,10 +442,10 @@ int r128_version(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_COPY(version.date, R128_DATE);
DRM_COPY(version.desc, R128_DESC);
- copy_to_user_ret((drm_version_t *)arg,
+ if (copy_to_user((drm_version_t *)arg,
&version,
- sizeof(version),
- -EFAULT);
+ sizeof(version)))
+ return -EFAULT;
return 0;
}
@@ -466,7 +467,7 @@ int r128_open(struct inode *inode, struct file *filp)
}
spin_unlock(&dev->count_lock);
}
-
+
return retcode;
}
@@ -500,7 +501,7 @@ int r128_release(struct inode *inode, struct file *filp)
}
spin_unlock(&dev->count_lock);
}
-
+
unlock_kernel();
return retcode;
}
@@ -559,7 +560,8 @@ int r128_lock(struct inode *inode, struct file *filp, unsigned int cmd,
dev->lck_start = start = get_cycles();
#endif
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
@@ -600,6 +602,7 @@ int r128_lock(struct inode *inode, struct file *filp, unsigned int cmd,
#endif
add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
if (!dev->lock.hw_lock) {
/* Device has been unregistered */
ret = -EINTR;
@@ -615,7 +618,6 @@ int r128_lock(struct inode *inode, struct file *filp, unsigned int cmd,
/* Contention */
atomic_inc(&dev->total_sleeps);
- current->state = TASK_INTERRUPTIBLE;
#if 1
current->policy |= SCHED_YIELD;
#endif
@@ -698,7 +700,8 @@ int r128_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_lock_t lock;
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index 5b15dddfb..63b98c727 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -11,11 +11,11 @@
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
@@ -23,7 +23,7 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
- *
+ *
* Authors: Rickard E. (Rik) Faith <faith@valinux.com>
* Kevin E. Martin <martin@valinux.com>
*
diff --git a/drivers/char/drm/tdfx_context.c b/drivers/char/drm/tdfx_context.c
index d6903c0ae..1fd733100 100644
--- a/drivers/char/drm/tdfx_context.c
+++ b/drivers/char/drm/tdfx_context.c
@@ -105,19 +105,21 @@ int tdfx_resctx(struct inode *inode, struct file *filp, unsigned int cmd,
int i;
DRM_DEBUG("%d\n", DRM_RESERVED_CONTEXTS);
- copy_from_user_ret(&res, (drm_ctx_res_t *)arg, sizeof(res), -EFAULT);
+ if (copy_from_user(&res, (drm_ctx_res_t *)arg, sizeof(res)))
+ return -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],
+ if (copy_to_user(&res.contexts[i],
&i,
- sizeof(i),
- -EFAULT);
+ sizeof(i)))
+ return -EFAULT;
}
}
res.count = DRM_RESERVED_CONTEXTS;
- copy_to_user_ret((drm_ctx_res_t *)arg, &res, sizeof(res), -EFAULT);
+ if (copy_to_user((drm_ctx_res_t *)arg, &res, sizeof(res)))
+ return -EFAULT;
return 0;
}
@@ -129,7 +131,8 @@ int tdfx_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
if ((ctx.handle = tdfx_alloc_queue(dev)) == DRM_KERNEL_CONTEXT) {
/* Skip kernel's context and get a new one. */
ctx.handle = tdfx_alloc_queue(dev);
@@ -141,7 +144,8 @@ int tdfx_addctx(struct inode *inode, struct file *filp, unsigned int cmd,
return -ENOMEM;
}
- copy_to_user_ret((drm_ctx_t *)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t *)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -150,7 +154,8 @@ int tdfx_modctx(struct inode *inode, struct file *filp, unsigned int cmd,
{
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+ return -EFAULT;
if (ctx.flags==_DRM_CONTEXT_PRESERVED)
tdfx_res_ctx.handle=ctx.handle;
return 0;
@@ -161,10 +166,12 @@ int tdfx_getctx(struct inode *inode, struct file *filp, unsigned int cmd,
{
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t*)arg, sizeof(ctx), -EFAULT);
- /* This is 0, because we don't hanlde any context flags */
+ if (copy_from_user(&ctx, (drm_ctx_t*)arg, sizeof(ctx)))
+ return -EFAULT;
+ /* This is 0, because we don't handle any context flags */
ctx.flags = 0;
- copy_to_user_ret((drm_ctx_t*)arg, &ctx, sizeof(ctx), -EFAULT);
+ if (copy_to_user((drm_ctx_t*)arg, &ctx, sizeof(ctx)))
+ return -EFAULT;
return 0;
}
@@ -175,7 +182,8 @@ int tdfx_switchctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
return tdfx_context_switch(dev, dev->last_context, ctx.handle);
}
@@ -187,7 +195,8 @@ int tdfx_newctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
tdfx_context_switch_complete(dev, ctx.handle);
@@ -201,7 +210,8 @@ int tdfx_rmctx(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_ctx_t ctx;
- copy_from_user_ret(&ctx, (drm_ctx_t *)arg, sizeof(ctx), -EFAULT);
+ if (copy_from_user(&ctx, (drm_ctx_t *)arg, sizeof(ctx)))
+ return -EFAULT;
DRM_DEBUG("%d\n", ctx.handle);
drm_ctxbitmap_free(dev, ctx.handle);
diff --git a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c
index 59f101970..5f2c804af 100644
--- a/drivers/char/drm/tdfx_drv.c
+++ b/drivers/char/drm/tdfx_drv.c
@@ -1,4 +1,4 @@
-/* tdfx.c -- tdfx driver -*- linux-c -*-
+/* tdfx_drv.c -- tdfx driver -*- linux-c -*-
* Created: Thu Oct 7 10:38:32 1999 by faith@precisioninsight.com
*
* Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
@@ -11,11 +11,11 @@
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
- *
+ *
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
@@ -23,7 +23,7 @@
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
- *
+ *
* Authors:
* Rickard E. (Rik) Faith <faith@valinux.com>
* Daryll Strauss <daryll@valinux.com>
@@ -36,7 +36,7 @@
#define TDFX_NAME "tdfx"
#define TDFX_DESC "3dfx Banshee/Voodoo3+"
-#define TDFX_DATE "20000719"
+#define TDFX_DATE "20000928"
#define TDFX_MAJOR 1
#define TDFX_MINOR 0
#define TDFX_PATCHLEVEL 0
@@ -76,7 +76,7 @@ static drm_ioctl_desc_t tdfx_ioctls[] = {
[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 },
-
+
[DRM_IOCTL_NR(DRM_IOCTL_ADD_CTX)] = { tdfx_addctx, 1, 1 },
[DRM_IOCTL_NR(DRM_IOCTL_RM_CTX)] = { tdfx_rmctx, 1, 1 },
[DRM_IOCTL_NR(DRM_IOCTL_MOD_CTX)] = { tdfx_modctx, 1, 1 },
@@ -128,7 +128,7 @@ __setup("tdfx=", tdfx_options);
static int tdfx_setup(drm_device_t *dev)
{
int i;
-
+
atomic_set(&dev->ioctl_count, 0);
atomic_set(&dev->vma_count, 0);
dev->buf_use = 0;
@@ -170,7 +170,7 @@ static int tdfx_setup(drm_device_t *dev)
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;
@@ -179,15 +179,15 @@ static int tdfx_setup(drm_device_t *dev)
init_waitqueue_head(&dev->buf_writers);
tdfx_res_ctx.handle=-1;
-
+
DRM_DEBUG("\n");
-
+
/* The kernel's context could be created here, but is now created
in drm_dma_enqueue. This is more resource-efficient for
hardware that does not do DMA, but may mean that
drm_select_queue fails between the time the interrupt is
initialized and the time the queues are initialized. */
-
+
return 0;
}
@@ -203,12 +203,12 @@ static int tdfx_takedown(drm_device_t *dev)
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;
@@ -227,7 +227,7 @@ static int tdfx_takedown(drm_device_t *dev)
if (dev->agp) {
drm_agp_mem_t *temp;
drm_agp_mem_t *temp_next;
-
+
temp = dev->agp->memory;
while(temp != NULL) {
temp_next = temp->next;
@@ -246,7 +246,7 @@ static int tdfx_takedown(drm_device_t *dev)
}
dev->vmalist = NULL;
}
-
+
/* Clear map area and mtrr information */
if (dev->maplist) {
for (i = 0; i < dev->map_count; i++) {
@@ -284,14 +284,14 @@ static int tdfx_takedown(drm_device_t *dev)
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;
}
@@ -308,7 +308,7 @@ static int tdfx_init(void)
memset((void *)dev, 0, sizeof(*dev));
dev->count_lock = SPIN_LOCK_UNLOCKED;
sema_init(&dev->struct_sem, 1);
-
+
#ifdef MODULE
drm_parse_options(tdfx);
#endif
@@ -340,7 +340,7 @@ static int tdfx_init(void)
TDFX_PATCHLEVEL,
TDFX_DATE,
tdfx_misc.minor);
-
+
return 0;
}
@@ -351,7 +351,7 @@ static void tdfx_cleanup(void)
drm_device_t *dev = &tdfx_device;
DRM_DEBUG("\n");
-
+
drm_proc_cleanup();
if (misc_deregister(&tdfx_misc)) {
DRM_ERROR("Cannot unload module\n");
@@ -379,17 +379,18 @@ int tdfx_version(struct inode *inode, struct file *filp, unsigned int cmd,
drm_version_t version;
int len;
- copy_from_user_ret(&version,
+ if (copy_from_user(&version,
(drm_version_t *)arg,
- sizeof(version),
- -EFAULT);
+ sizeof(version)))
+ return -EFAULT;
#define DRM_COPY(name,value) \
len = strlen(value); \
if (len > name##_len) len = name##_len; \
name##_len = strlen(value); \
if (len && name) { \
- copy_to_user_ret(name, value, len, -EFAULT); \
+ if (copy_to_user(name, value, len)) \
+ return -EFAULT; \
}
version.version_major = TDFX_MAJOR;
@@ -400,10 +401,10 @@ int tdfx_version(struct inode *inode, struct file *filp, unsigned int cmd,
DRM_COPY(version.date, TDFX_DATE);
DRM_COPY(version.desc, TDFX_DESC);
- copy_to_user_ret((drm_version_t *)arg,
+ if (copy_to_user((drm_version_t *)arg,
&version,
- sizeof(version),
- -EFAULT);
+ sizeof(version)))
+ return -EFAULT;
return 0;
}
@@ -411,7 +412,7 @@ int tdfx_open(struct inode *inode, struct file *filp)
{
drm_device_t *dev = &tdfx_device;
int retcode = 0;
-
+
DRM_DEBUG("open_count = %d\n", dev->open_count);
if (!(retcode = drm_open_helper(inode, filp, dev))) {
#if LINUX_VERSION_CODE < 0x020333
@@ -479,7 +480,7 @@ int tdfx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
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);
@@ -499,7 +500,7 @@ int tdfx_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
retcode = (func)(inode, filp, cmd, arg);
}
}
-
+
atomic_dec(&dev->ioctl_count);
return retcode;
}
@@ -518,7 +519,8 @@ int tdfx_lock(struct inode *inode, struct file *filp, unsigned int cmd,
dev->lck_start = start = get_cycles();
#endif
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
@@ -536,7 +538,7 @@ int tdfx_lock(struct inode *inode, struct file *filp, unsigned int cmd,
if (lock.context < 0 || lock.context >= dev->queue_count)
return -EINVAL;
#endif
-
+
if (!ret) {
#if 0
if (_DRM_LOCKING_CONTEXT(dev->lock.hw_lock->lock)
@@ -548,7 +550,7 @@ int tdfx_lock(struct inode *inode, struct file *filp, unsigned int cmd,
/* Can't take lock if we just had it and
there is contention. */
DRM_DEBUG("%d (pid %d) delayed j=%d dev=%d jiffies=%d\n",
- lock.context, current->pid, j,
+ lock.context, current->pid, j,
dev->lock.lock_time, jiffies);
current->state = TASK_INTERRUPTIBLE;
current->policy |= SCHED_YIELD;
@@ -559,6 +561,7 @@ int tdfx_lock(struct inode *inode, struct file *filp, unsigned int cmd,
#endif
add_wait_queue(&dev->lock.lock_queue, &entry);
for (;;) {
+ current->state = TASK_INTERRUPTIBLE;
if (!dev->lock.hw_lock) {
/* Device has been unregistered */
ret = -EINTR;
@@ -571,10 +574,9 @@ int tdfx_lock(struct inode *inode, struct file *filp, unsigned int cmd,
atomic_inc(&dev->total_locks);
break; /* Got lock */
}
-
+
/* Contention */
atomic_inc(&dev->total_sleeps);
- current->state = TASK_INTERRUPTIBLE;
#if 1
current->policy |= SCHED_YIELD;
#endif
@@ -615,6 +617,15 @@ int tdfx_lock(struct inode *inode, struct file *filp, unsigned int cmd,
#endif
if (!ret) {
+ sigemptyset(&dev->sigmask);
+ sigaddset(&dev->sigmask, SIGSTOP);
+ sigaddset(&dev->sigmask, SIGTSTP);
+ sigaddset(&dev->sigmask, SIGTTIN);
+ sigaddset(&dev->sigmask, SIGTTOU);
+ dev->sigdata.context = lock.context;
+ dev->sigdata.lock = dev->lock.hw_lock;
+ block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask);
+
if (lock.flags & _DRM_LOCK_READY) {
/* Wait for space in DMA/FIFO */
}
@@ -637,7 +648,7 @@ int tdfx_lock(struct inode *inode, struct file *filp, unsigned int cmd,
#if DRM_DMA_HISTOGRAM
atomic_inc(&dev->histo.lacq[drm_histogram_slot(get_cycles() - start)]);
#endif
-
+
return ret;
}
@@ -649,8 +660,9 @@ int tdfx_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
drm_device_t *dev = priv->dev;
drm_lock_t lock;
- copy_from_user_ret(&lock, (drm_lock_t *)arg, sizeof(lock), -EFAULT);
-
+ if (copy_from_user(&lock, (drm_lock_t *)arg, sizeof(lock)))
+ return -EFAULT;
+
if (lock.context == DRM_KERNEL_CONTEXT) {
DRM_ERROR("Process %d using kernel context %d\n",
current->pid, lock.context);
@@ -678,6 +690,7 @@ int tdfx_unlock(struct inode *inode, struct file *filp, unsigned int cmd,
current->priority = DEF_PRIORITY;
}
#endif
-
+
+ unblock_all_signals();
return 0;
}
diff --git a/drivers/char/drm/vm.c b/drivers/char/drm/vm.c
index 7c5a24bc9..964921b46 100644
--- a/drivers/char/drm/vm.c
+++ b/drivers/char/drm/vm.c
@@ -67,8 +67,6 @@ struct page *drm_vm_nopage(struct vm_area_struct *vma,
int write_access)
#endif
{
- DRM_DEBUG("0x%08lx, %d\n", address, write_access);
-
return NOPAGE_SIGBUS; /* Disallow mremap */
}
diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c
index 4639f34eb..66e185c10 100644
--- a/drivers/char/efirtc.c
+++ b/drivers/char/efirtc.c
@@ -249,7 +249,7 @@ efi_rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
convert_from_efi_time(&eft, &wtime);
- return copy_to_user((void *)&ewp->time, &wtime, sizeof(struct rtc_time));
+ return copy_to_user((void *)&ewp->time, &wtime, sizeof(struct rtc_time)) ? -EFAULT : 0;
}
return -EINVAL;
}
diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c
index 77ee01ecf..d828e831d 100644
--- a/drivers/char/ftape/lowlevel/ftape-calibr.c
+++ b/drivers/char/ftape/lowlevel/ftape-calibr.c
@@ -183,7 +183,7 @@ static void init_clock(void)
}
#elif defined(__alpha__)
#if CONFIG_FT_ALPHA_CLOCK == 0
-#error You must define and set CONFIG_FT_ALPHA_CLOCK in the Makefile !
+#error You must define and set CONFIG_FT_ALPHA_CLOCK in 'make config' !
#endif
extern struct hwrpb_struct *hwrpb;
TRACE_FUN(ft_t_any);
diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.c b/drivers/char/ftape/lowlevel/ftape-ctl.c
index 6ec456f00..4196458d0 100644
--- a/drivers/char/ftape/lowlevel/ftape-ctl.c
+++ b/drivers/char/ftape/lowlevel/ftape-ctl.c
@@ -794,8 +794,8 @@ void ftape_disable(void)
i, *ft_buffer[i]->address);
}
}
- if (sigtestsetmask(&current->signal, _DONT_BLOCK) &&
- !(sigtestsetmask(&current->signal, _NEVER_BLOCK)) &&
+ if (sigtestsetmask(&current->pending.signal, _DONT_BLOCK) &&
+ !(sigtestsetmask(&current->pending.signal, _NEVER_BLOCK)) &&
ftape_tape_running) {
TRACE(ft_t_warn,
"Interrupted by fatal signal and tape still running");
diff --git a/drivers/char/ftape/lowlevel/ftape-rw.c b/drivers/char/ftape/lowlevel/ftape-rw.c
index 2ae96344e..2c14f468e 100644
--- a/drivers/char/ftape/lowlevel/ftape-rw.c
+++ b/drivers/char/ftape/lowlevel/ftape-rw.c
@@ -433,7 +433,7 @@ int ftape_dumb_stop(void)
result = ftape_ready_wait(ftape_timeout.pause,&status);
}
} while (ftape_tape_running
- && !(sigtestsetmask(&current->signal, _NEVER_BLOCK)));
+ && !(sigtestsetmask(&current->pending.signal, _NEVER_BLOCK)));
#ifndef TESTING
ft_location.known = 0;
#endif
@@ -661,7 +661,7 @@ static int seek_forward(int segment_id, int fast)
* to find a way to skip an EMPTY_SEGMENT. !!! FIXME !!!
*/
if (ftape_read_id() < 0 || !ft_location.known ||
- sigtestsetmask(&current->signal, _DONT_BLOCK)) {
+ sigtestsetmask(&current->pending.signal, _DONT_BLOCK)) {
ft_location.known = 0;
if (!ftape_tape_running ||
++failures > FT_SECTORS_PER_SEGMENT) {
@@ -776,7 +776,7 @@ static int skip_reverse(int segment_id, int *pstatus)
fast_seek(count, 1);
logical_forward();
if (ftape_read_id() < 0 || !ft_location.known ||
- (sigtestsetmask(&current->signal, _DONT_BLOCK))) {
+ (sigtestsetmask(&current->pending.signal, _DONT_BLOCK))) {
if ((!ftape_tape_running && !ft_location.known) ||
++failures > FT_SECTORS_PER_SEGMENT) {
TRACE_ABORT(-EIO, ft_t_err,
@@ -1002,7 +1002,7 @@ int ftape_start_tape(int segment_id, int sector_offset)
while (result < 0 &&
retry++ <= 5 &&
!ft_failure &&
- !(sigtestsetmask(&current->signal, _DONT_BLOCK))) {
+ !(sigtestsetmask(&current->pending.signal, _DONT_BLOCK))) {
if (retry && start_offset < 5) {
start_offset ++;
diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.h b/drivers/char/ftape/lowlevel/ftape-tracing.h
index e0f7e0f4f..77af02f69 100644
--- a/drivers/char/ftape/lowlevel/ftape-tracing.h
+++ b/drivers/char/ftape/lowlevel/ftape-tracing.h
@@ -171,7 +171,7 @@ extern void ftape_trace_log (const char *file, const char *name);
* but rather into ftape-rw.h (maybe)
*/
#define FT_SIGNAL_EXIT(sig_mask) \
- if (sigtestsetmask(&current->signal, sig_mask)) { \
+ if (sigtestsetmask(&current->pending.signal, sig_mask)) { \
TRACE_ABORT(-EINTR, \
ft_t_warn, \
"interrupted by non-blockable signal"); \
diff --git a/drivers/char/hp600_keyb.c b/drivers/char/hp600_keyb.c
index 4a109265a..f2e15fc63 100644
--- a/drivers/char/hp600_keyb.c
+++ b/drivers/char/hp600_keyb.c
@@ -7,7 +7,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
-#include <asm/delay.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include "scan_keyb.h"
diff --git a/drivers/char/i810-tco.c b/drivers/char/i810-tco.c
index fcd105d35..b01564030 100644
--- a/drivers/char/i810-tco.c
+++ b/drivers/char/i810-tco.c
@@ -301,10 +301,9 @@ static int __init watchdog_init (void)
tco_timer_settimer ((unsigned char) i810_margin);
tco_timer_reload ();
- /* FIXME: no floating point math */
printk (KERN_INFO
"i810 TCO timer: V0.02, timer margin: %d sec (0x%04x)\n",
- (int) (i810_margin * 0.6), TCOBASE);
+ (int) (i810_margin * 6 / 10), TCOBASE);
return 0;
}
diff --git a/drivers/char/i810_rng.c b/drivers/char/i810_rng.c
index 7a6718c02..18e198f51 100644
--- a/drivers/char/i810_rng.c
+++ b/drivers/char/i810_rng.c
@@ -119,13 +119,6 @@
* The timer and the character device may be used simultaneously,
if desired.
- * FIXME: Currently only one open() of the character device is allowed.
- If another user tries to open() the device, they will get an
- -EBUSY error. Instead, this really should either support
- multiple simultaneous users of the character device (not hard),
- or simply block open() until the current user of the chrdev
- calls close().
-
* FIXME: support poll()
* FIXME: should we be crazy and support mmap()?
@@ -138,11 +131,16 @@
This will slow things down but guarantee that bad data is
never passed upstream.
+ * Since the RNG is accessed from a timer as well as normal
+ kernel code, but not from interrupts, we use spin_lock_bh
+ in regular code, and spin_lock in the timer function, to
+ serialize access to the RNG hardware area.
+
----------------------------------------------------------
Change history:
- 0.6.2:
+ Version 0.6.2:
* Clean up spinlocks. Since we don't have any interrupts
to worry about, but we do have a timer to worry about,
we use spin_lock_bh everywhere except the timer function
@@ -152,6 +150,20 @@
* New timer interval sysctl
* Clean up sysctl names
+ Version 0.9.0:
+ * Don't register a pci_driver, because we are really
+ using PCI bridge vendor/device ids, and someone
+ may want to register a driver for the bridge. (bug fix)
+ * Don't let the usage count go negative (bug fix)
+ * Clean up spinlocks (bug fix)
+ * Enable PCI device, if necessary (bug fix)
+ * iounmap on module unload (bug fix)
+ * If RNG chrdev is already in use when open(2) is called,
+ sleep until it is available.
+ * Remove redundant globals rng_allocated, rng_use_count
+ * Convert numeric globals to unsigned
+ * Module unload cleanup
+
*/
@@ -166,6 +178,7 @@
#include <linux/sysctl.h>
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
+#include <linux/mm.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -174,7 +187,7 @@
/*
* core module and version information
*/
-#define RNG_VERSION "0.6.2"
+#define RNG_VERSION "0.9.0"
#define RNG_MODULE_NAME "i810_rng"
#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION
#define PFX RNG_MODULE_NAME ": "
@@ -253,22 +266,24 @@ static void rng_run_fips_test (void);
* various RNG status variables. they are globals
* as we only support a single RNG device
*/
-static int rng_allocated; /* is someone using the RNG region? */
static int rng_hw_enabled; /* is the RNG h/w enabled? */
static int rng_timer_enabled; /* is the RNG timer enabled? */
-static int rng_use_count; /* number of times RNG has been enabled */
static int rng_trusted; /* 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_interval_sysctl; /* sysctl for changing timer interval */
+static unsigned int rng_entropy = 8; /* number of entropy bits we submit to /dev/random */
+static unsigned int rng_entropy_sysctl; /* sysctl for changing entropy bits */
+static unsigned int rng_interval_sysctl; /* sysctl for changing timer interval */
static int rng_have_mem_region; /* did we grab RNG region via request_mem_region? */
-static int rng_fips_counter; /* size of internal FIPS test data pool */
-static int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */
+static unsigned int rng_fips_counter; /* size of internal FIPS test data pool */
+static unsigned int rng_timer_len = RNG_DEF_TIMER_LEN; /* timer interval, in jiffies */
static void *rng_mem; /* 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 int rng_open; /* boolean, 0 (false) if chrdev is closed, 1 (true) if open */
+static struct pci_dev *rng_pdev; /* Firmware Hub PCI device found during PCI probe */
+static struct semaphore rng_open_sem; /* Semaphore for serializing rng_open/release */
+static wait_queue_head_t rng_open_wait; /* Wait queue for serializing open/release */
+static int rng_open_mode; /* Open mode (we only allow reads) */
+
/*
* inlined helper functions for accessing RNG registers
@@ -320,6 +335,8 @@ static void rng_timer_tick (unsigned long data)
/* gimme some thermal noise, baby */
rng_data = rng_data_read ();
+ spin_unlock (&rng_lock);
+
/*
* if RNG has been verified in the past, add
* data just read to the /dev/random pool,
@@ -333,6 +350,8 @@ static void rng_timer_tick (unsigned long data)
rng_fips_test_store (rng_data);
if (rng_fips_counter > RNG_FIPS_TEST_THRESHOLD)
rng_run_fips_test ();
+ } else {
+ spin_unlock (&rng_lock);
}
/* run the timer again, if enabled */
@@ -340,9 +359,6 @@ static void rng_timer_tick (unsigned long data)
rng_timer.expires = jiffies + rng_timer_len;
add_timer (&rng_timer);
}
-
- spin_unlock (&rng_lock);
-
}
@@ -351,8 +367,8 @@ static void rng_timer_tick (unsigned long data)
*/
static int rng_enable (int enable)
{
- int rc = 0;
- u8 hw_status;
+ int rc = 0, action = 0;
+ u8 hw_status, new_status;
DPRINTK ("ENTER\n");
@@ -362,28 +378,36 @@ static int rng_enable (int enable)
if (enable) {
rng_hw_enabled = 1;
- rng_use_count++;
MOD_INC_USE_COUNT;
} else {
- rng_use_count--;
- if (rng_use_count == 0)
+#ifndef __alpha__
+ if (GET_USE_COUNT (THIS_MODULE) > 0)
+ MOD_DEC_USE_COUNT;
+ if (GET_USE_COUNT (THIS_MODULE) == 0)
rng_hw_enabled = 0;
- MOD_DEC_USE_COUNT;
+#endif
}
if (rng_hw_enabled && ((hw_status & RNG_ENABLED) == 0)) {
rng_hwstatus_set (hw_status | RNG_ENABLED);
- printk (KERN_INFO PFX "RNG h/w enabled\n");
+ action = 1;
}
else if (!rng_hw_enabled && (hw_status & RNG_ENABLED)) {
rng_hwstatus_set (hw_status & ~RNG_ENABLED);
- printk (KERN_INFO PFX "RNG h/w disabled\n");
+ action = 2;
}
+ new_status = rng_hwstatus ();
+
spin_unlock_bh (&rng_lock);
- if ((!!enable) != (!!(rng_hwstatus () & RNG_ENABLED))) {
+ if (action == 1)
+ printk (KERN_INFO PFX "RNG h/w enabled\n");
+ else if (action == 2)
+ printk (KERN_INFO PFX "RNG h/w disabled\n");
+
+ if ((!!enable) != (!!(new_status & RNG_ENABLED))) {
printk (KERN_ERR PFX "Unable to %sable the RNG\n",
enable ? "en" : "dis");
rc = -EIO;
@@ -406,15 +430,14 @@ static int rng_handle_sysctl_enable (ctl_table * table, int write, struct file *
DPRINTK ("ENTER\n");
spin_lock_bh (&rng_lock);
-
rng_enabled_sysctl = enabled_save = rng_timer_enabled;
+ spin_unlock_bh (&rng_lock);
rc = proc_dointvec (table, write, filp, buffer, lenp);
- if (rc) {
- spin_unlock_bh (&rng_lock);
+ if (rc)
return rc;
- }
+ spin_lock_bh (&rng_lock);
if (enabled_save != rng_enabled_sysctl) {
rng_timer_enabled = rng_enabled_sysctl;
spin_unlock_bh (&rng_lock);
@@ -591,53 +614,49 @@ static int rng_dev_open (struct inode *inode, struct file *filp)
int rc = -EINVAL;
if ((filp->f_mode & FMODE_READ) == 0)
- goto err_out;
+ goto err_out_ret;
if (filp->f_mode & FMODE_WRITE)
- goto err_out;
+ goto err_out_ret;
- spin_lock_bh (&rng_lock);
-
- /* only allow one open of this device, exit with -EBUSY if already open */
- /* FIXME: we should sleep on a semaphore here, unless O_NONBLOCK */
- if (rng_open) {
- spin_unlock_bh (&rng_lock);
- rc = -EBUSY;
- goto err_out;
+ /* wait for device to become free */
+ down (&rng_open_sem);
+ while (rng_open_mode & filp->f_mode) {
+ if (filp->f_flags & O_NONBLOCK) {
+ up (&rng_open_sem);
+ return -EWOULDBLOCK;
+ }
+ up (&rng_open_sem);
+ interruptible_sleep_on (&rng_open_wait);
+ if (signal_pending (current))
+ return -ERESTARTSYS;
+ down (&rng_open_sem);
}
- rng_open = 1;
-
- spin_unlock_bh (&rng_lock);
-
- if (rng_enable(1) != 0) {
- spin_lock_bh (&rng_lock);
- rng_open = 0;
- spin_unlock_bh (&rng_lock);
+ if (rng_enable (1)) {
rc = -EIO;
goto err_out;
}
+ rng_open_mode |= filp->f_mode & (FMODE_READ | FMODE_WRITE);
+ up (&rng_open_sem);
return 0;
err_out:
+ up (&rng_open_sem);
+err_out_ret:
return rc;
}
static int rng_dev_release (struct inode *inode, struct file *filp)
{
+ down(&rng_open_sem);
- lock_kernel();
- if (rng_enable(0) != 0) {
- unlock_kernel();
- return -EIO;
- }
-
- spin_lock_bh (&rng_lock);
- rng_open = 0;
- spin_unlock_bh (&rng_lock);
- unlock_kernel();
+ rng_enable(0);
+ rng_open_mode &= (~filp->f_mode) & (FMODE_READ|FMODE_WRITE);
+ up (&rng_open_sem);
+ wake_up (&rng_open_wait);
return 0;
}
@@ -705,19 +724,15 @@ 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)
+static int __init rng_init_one (struct pci_dev *dev)
{
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;
- }
+ if (pci_enable_device (dev))
+ return -EIO;
/* XXX currently fails, investigate who has our mem region */
if (request_mem_region (RNG_ADDR, RNG_ADDR_LEN, RNG_MODULE_NAME))
@@ -728,7 +743,7 @@ static int __init rng_init_one (struct pci_dev *dev,
printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
DPRINTK ("EXIT, returning -EBUSY\n");
rc = -EBUSY;
- goto err_out;
+ goto err_out_free_res;
}
/* Check for Intel 82802 */
@@ -737,11 +752,9 @@ static int __init rng_init_one (struct pci_dev *dev,
printk (KERN_ERR PFX "RNG not detected\n");
DPRINTK ("EXIT, returning -ENODEV\n");
rc = -ENODEV;
- goto err_out;
+ goto err_out_free_map;
}
- rng_allocated = 1;
-
if (rng_entropy < 0 || rng_entropy > RNG_MAX_ENTROPY)
rng_entropy = RNG_MAX_ENTROPY;
@@ -749,10 +762,11 @@ static int __init rng_init_one (struct pci_dev *dev,
init_timer (&rng_timer);
rng_timer.function = rng_timer_tick;
+ /* turn RNG h/w off, if it's on */
rc = rng_enable (0);
if (rc) {
printk (KERN_ERR PFX "cannot disable RNG, aborting\n");
- goto err_out;
+ goto err_out_free_map;
}
/* add sysctls */
@@ -761,9 +775,9 @@ static int __init rng_init_one (struct pci_dev *dev,
DPRINTK ("EXIT, returning 0\n");
return 0;
-err_out:
- if (rng_mem)
- iounmap (rng_mem);
+err_out_free_map:
+ iounmap (rng_mem);
+err_out_free_res:
if (rng_have_mem_region)
release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
return rc;
@@ -772,6 +786,11 @@ err_out:
/*
* Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE. We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
*/
const static struct pci_device_id rng_pci_tbl[] __initdata = {
{ 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, },
@@ -780,11 +799,6 @@ const static struct pci_device_id rng_pci_tbl[] __initdata = {
};
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");
@@ -813,23 +827,36 @@ static struct miscdevice rng_miscdev = {
static int __init rng_init (void)
{
int rc;
+ struct pci_dev *pdev;
DPRINTK ("ENTER\n");
- if (pci_register_driver (&rng_driver) < 1) {
- DPRINTK ("EXIT, returning -ENODEV\n");
+ init_MUTEX (&rng_open_sem);
+ init_waitqueue_head (&rng_open_wait);
+
+ pdev = pci_find_device (0x8086, 0x2418, NULL);
+ if (!pdev)
+ pdev = pci_find_device (0x8086, 0x2428, NULL);
+ if (!pdev)
return -ENODEV;
- }
+
+ rc = rng_init_one (pdev);
+ if (rc)
+ return rc;
rc = misc_register (&rng_miscdev);
if (rc) {
- pci_unregister_driver (&rng_driver);
+ iounmap (rng_mem);
+ if (rng_have_mem_region)
+ release_mem_region (RNG_ADDR, RNG_ADDR_LEN);
DPRINTK ("EXIT, returning %d\n", rc);
return rc;
}
printk (KERN_INFO RNG_DRIVER_NAME " loaded\n");
+ rng_pdev = pdev;
+
DPRINTK ("EXIT, returning 0\n");
return 0;
}
@@ -842,18 +869,17 @@ static void __exit rng_cleanup (void)
{
DPRINTK ("ENTER\n");
- del_timer_sync (&rng_timer);
+ assert (rng_timer_enabled == 0);
+ assert (rng_hw_enabled == 0);
+
+ misc_deregister (&rng_miscdev);
rng_sysctl (0);
- pci_unregister_driver (&rng_driver);
+ iounmap (rng_mem);
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");
}
diff --git a/drivers/char/joystick/pcigame.c b/drivers/char/joystick/pcigame.c
index 0348ba08b..50ea4e44d 100644
--- a/drivers/char/joystick/pcigame.c
+++ b/drivers/char/joystick/pcigame.c
@@ -40,8 +40,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/pci_ids.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/gameport.h>
#define PCI_VENDOR_ID_AUREAL 0x12eb
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index 5be8baee8..2e9e170c4 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -712,11 +712,12 @@ static void lp_attach (struct parport *port)
if (parport_nr[0] == LP_PARPORT_AUTO &&
port->probe_info[0].class != PARPORT_CLASS_PRINTER)
return;
-
+ if (lp_count == LP_NO) {
+ printk("lp: ignoring parallel port (max. %d)\n",LP_NO);
+ return;
+ }
if (!lp_register(lp_count, port))
- if (++lp_count == LP_NO)
- break;
-
+ lp_count++;
break;
default:
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 3b5a2c497..71e03fed5 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -28,12 +28,6 @@
#ifdef CONFIG_I2C
extern int i2c_init_all(void);
#endif
-#ifdef CONFIG_SOUND
-void soundcore_init(void);
-#ifdef CONFIG_SOUND_OSS
-void soundcard_init(void);
-#endif
-#endif
#ifdef CONFIG_SPARCAUDIO
extern int sparcaudio_init(void);
#endif
@@ -55,9 +49,6 @@ extern void mda_console_init(void);
#if defined(CONFIG_ADB)
extern void adbdev_init(void);
#endif
-#ifdef CONFIG_PHONE
-extern void telephony_init(void);
-#endif
static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
const char * buf, size_t count, loff_t *ppos)
@@ -258,25 +249,27 @@ static ssize_t read_kmem(struct file *file, char *buf,
count -= read;
}
- kbuf = (char *)__get_free_page(GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
- while (count > 0) {
- int len = count;
-
- if (len > PAGE_SIZE)
- len = PAGE_SIZE;
- len = vread(kbuf, (char *)p, len);
- if (len && copy_to_user(buf, kbuf, len)) {
- free_page((unsigned long)kbuf);
- return -EFAULT;
+ if (count > 0) {
+ kbuf = (char *)__get_free_page(GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+ while (count > 0) {
+ int len = count;
+
+ if (len > PAGE_SIZE)
+ len = PAGE_SIZE;
+ len = vread(kbuf, (char *)p, len);
+ if (len && copy_to_user(buf, kbuf, len)) {
+ free_page((unsigned long)kbuf);
+ return -EFAULT;
+ }
+ count -= len;
+ buf += len;
+ virtr += len;
+ p += len;
}
- count -= len;
- buf += len;
- virtr += len;
- p += len;
+ free_page((unsigned long)kbuf);
}
- free_page((unsigned long)kbuf);
*ppos = p;
return virtr + read;
}
@@ -644,15 +637,6 @@ int __init chr_dev_init(void)
lp_m68k_init();
#endif
misc_init();
-#ifdef CONFIG_SOUND
- soundcore_init();
-#ifdef CONFIG_SOUND_OSS
- soundcard_init();
-#endif
-#endif
-#ifdef CONFIG_SPARCAUDIO
- sparcaudio_init();
-#endif
#if CONFIG_QIC02_TAPE
qic02_tape_init();
#endif
@@ -668,8 +652,5 @@ int __init chr_dev_init(void)
#ifdef CONFIG_VIDEO_DEV
videodev_init();
#endif
-#ifdef CONFIG_PHONE
- telephony_init();
-#endif
return 0;
}
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index aee35a3eb..95dbdaab2 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -70,8 +70,6 @@ extern int psaux_init(void);
extern void gfx_register(void);
#endif
extern void streamable_init(void);
-extern void watchdog_init(void);
-extern void pcwatchdog_init(void);
extern int rtc_sun_init(void); /* Combines MK48T02 and MK48T08 */
extern int rtc_DP8570A_init(void);
extern int rtc_MK48T08_init(void);
@@ -81,6 +79,7 @@ extern int radio_init(void);
extern int pc110pad_init(void);
extern int pmu_device_init(void);
extern int qpmouse_init(void);
+extern int tosh_init(void);
static int misc_read_proc(char *buf, char **start, off_t offset,
int len, int *eof, void *private)
@@ -254,18 +253,6 @@ int __init misc_init(void)
#ifdef CONFIG_PC110_PAD
pc110pad_init();
#endif
-/*
- * Only one watchdog can succeed. We probe the pcwatchdog first,
- * then the wdt cards and finally the software watchdog which always
- * works. This means if your hardware watchdog dies or is 'borrowed'
- * for some reason the software watchdog still gives you some cover.
- */
-#ifdef CONFIG_PCWATCHDOG
- pcwatchdog_init();
-#endif
-#ifdef CONFIG_SOFT_WATCHDOG
- watchdog_init();
-#endif
#ifdef CONFIG_MVME16x
rtc_MK48T08_init();
#endif
@@ -299,6 +286,9 @@ int __init misc_init(void)
#ifdef CONFIG_SGI
streamable_init ();
#endif
+#ifdef CONFIG_TOSHIBA
+ tosh_init();
+#endif
if (devfs_register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
diff --git a/drivers/char/mixcomwd.c b/drivers/char/mixcomwd.c
index 1daff0de7..90f16ca35 100644
--- a/drivers/char/mixcomwd.c
+++ b/drivers/char/mixcomwd.c
@@ -216,9 +216,10 @@ static int __init flashcom_checkcard(int port)
return 1;
}
-void __init mixcomwd_init(void)
+static int __init mixcomwd_init(void)
{
int i;
+ int ret;
int found=0;
for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) {
@@ -238,23 +239,21 @@ void __init mixcomwd_init(void)
if (!found) {
printk("mixcomwd: No card detected, or port not available.\n");
- return;
+ return -ENODEV;
}
request_region(watchdog_port,1,"MixCOM watchdog");
- misc_register(&mixcomwd_miscdev);
+ ret = misc_register(&mixcomwd_miscdev);
+ if (ret)
+ return ret;
+
printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port);
-}
-#ifdef MODULE
-int init_module(void)
-{
- mixcomwd_init();
return 0;
-}
+}
-void cleanup_module(void)
+static void __exit mixcomwd_exit(void)
{
#ifndef CONFIG_WATCHDOG_NOWAYOUT
if(mixcomwd_timer_alive) {
@@ -267,4 +266,6 @@ void cleanup_module(void)
release_region(watchdog_port,1);
misc_deregister(&mixcomwd_miscdev);
}
-#endif
+
+module_init(mixcomwd_init);
+module_exit(mixcomwd_exit);
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index a8c29311f..52eb41ad3 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -109,7 +109,7 @@
extern spinlock_t rtc_lock;
-static int nvram_open_cnt = 0; /* #times opened */
+static int nvram_open_cnt; /* #times opened */
static int nvram_open_mode; /* special open modes */
#define NVRAM_WRITE 1 /* opened for writing (exclusive) */
#define NVRAM_EXCL 2 /* opened with O_EXCL */
@@ -415,14 +415,29 @@ static struct miscdevice nvram_dev = {
static int __init nvram_init(void)
{
+ int ret;
+
/* First test whether the driver should init at all */
if (!CHECK_DRIVER_INIT())
return( -ENXIO );
- printk(KERN_INFO "Non-volatile memory driver v%s\n", NVRAM_VERSION );
- misc_register( &nvram_dev );
- create_proc_read_entry("driver/nvram",0,0,nvram_read_proc,NULL);
- return( 0 );
+ ret = misc_register( &nvram_dev );
+ if (ret) {
+ printk(KERN_ERR "nvram: can't misc_register on minor=%d\n", NVRAM_MINOR);
+ goto out;
+ }
+ if (!create_proc_read_entry("driver/nvram",0,0,nvram_read_proc,NULL)) {
+ printk(KERN_ERR "nvram: can't create /proc/driver/nvram\n");
+ ret = -ENOMEM;
+ goto outmisc;
+ }
+ ret = 0;
+ printk(KERN_INFO "Non-volatile memory driver v" NVRAM_VERSION "\n");
+out:
+ return( ret );
+outmisc:
+ misc_deregister( &nvram_dev );
+ goto out;
}
static void __exit nvram_cleanup_module (void)
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index 8b5c266a6..34aa6cfbd 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -1,6 +1,9 @@
/*
* Flash memory interface rev.5 driver for the Intel
* Flash chips used on the NetWinder.
+ *
+ * 20/08/2000 RMK use __ioremap to map flash into virtual memory
+ * make a few more places use "volatile"
*/
#include <linux/module.h>
@@ -15,7 +18,7 @@
#include <linux/spinlock.h>
#include <linux/init.h>
-#include <asm/dec21285.h>
+#include <asm/hardware/dec21285.h>
#include <asm/io.h>
#include <asm/leds.h>
#include <asm/mach-types.h>
@@ -33,7 +36,7 @@
#define MSTATIC
#endif
-#define NWFLASH_VERSION "6.2"
+#define NWFLASH_VERSION "6.3"
MSTATIC void kick_open(void);
MSTATIC int get_flash_id(void);
@@ -54,6 +57,7 @@ static int flashdebug; //if set - we will display progress msgs
static int gbWriteEnable;
static int gbWriteBase64Enable;
+static volatile unsigned char *FLASH_BASE;
MSTATIC int gbFlashSize = KFLASH_SIZE;
extern spinlock_t gpio_lock;
@@ -93,25 +97,25 @@ MSTATIC int get_flash_id(void)
*/
kick_open();
c2 = inb(0x80);
- *(unsigned char *) (FLASH_BASE + 0x8000) = 0x90;
+ *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0x90;
udelay(15);
- c1 = *(unsigned char *) FLASH_BASE;
+ c1 = *(volatile unsigned char *) FLASH_BASE;
c2 = inb(0x80);
/*
* on 4 Meg flash the second byte is actually at offset 2...
*/
if (c1 == 0xB0)
- c2 = *(unsigned char *) (FLASH_BASE + 2);
+ c2 = *(volatile unsigned char *) (FLASH_BASE + 2);
else
- c2 = *(unsigned char *) (FLASH_BASE + 1);
+ c2 = *(volatile unsigned char *) (FLASH_BASE + 1);
c2 += (c1 << 8);
/*
* set it back to read mode
*/
- *(unsigned char *) (FLASH_BASE + 0x8000) = 0xFF;
+ *(volatile unsigned char *) (FLASH_BASE + 0x8000) = 0xFF;
if (c2 == KFLASH_ID4)
gbFlashSize = KFLASH_SIZE4;
@@ -177,14 +181,9 @@ static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * p
if (count > gbFlashSize - p)
count = gbFlashSize - p;
- /*
- * flash virtual address
- */
- p += FLASH_BASE;
-
read = 0;
- if (copy_to_user(buf, (void *) p, count))
+ if (copy_to_user(buf, (void *)(FLASH_BASE + p), count))
return -EFAULT;
read += count;
file->f_pos += read;
@@ -193,15 +192,15 @@ static ssize_t flash_read(struct file *file, char *buf, size_t count, loff_t * p
static ssize_t flash_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
{
+ struct inode *inode = file->f_dentry->d_inode;
unsigned long p = file->f_pos;
int written;
int nBlock, temp, rc;
int i, j;
-
if (flashdebug)
- printk("Flash_dev: flash_write: offset=0x%X, buffer=0x%X, count=0x%X.\n",
- (unsigned int) p, (unsigned int) buf, count);
+ printk("flash_write: offset=0x%lX, buffer=0x%p, count=0x%X.\n",
+ p, buf, count);
if (!gbWriteEnable)
return -EINVAL;
@@ -209,20 +208,25 @@ static ssize_t flash_write(struct file *file, const char *buf, size_t count, lof
if (p < 64 * 1024 && (!gbWriteBase64Enable))
return -EINVAL;
- if (count < 0)
- return -EINVAL;
-
/*
- * if write size to big - error!
+ * if byte count is -ve or to big - error!
*/
- if (count > gbFlashSize - p)
+ if (count < 0 || count > gbFlashSize - p)
return -EINVAL;
-
if (verify_area(VERIFY_READ, buf, count))
return -EFAULT;
+ /*
+ * We now should lock around writes. Really, we shouldn't
+ * allow the flash to be opened more than once in write
+ * mode though (note that you can't stop two processes having
+ * it open even then). --rmk
+ */
+ if (down_interruptible(&inode->i_sem))
+ return -ERESTARTSYS;
+
written = 0;
leds_event(led_claim);
@@ -310,6 +314,8 @@ static ssize_t flash_write(struct file *file, const char *buf, size_t count, lof
*/
leds_event(led_release);
+ up(&inode->i_sem);
+
return written;
}
@@ -586,7 +592,7 @@ MSTATIC int write_block(unsigned long p, const char *buf, int count)
if (time_before(jiffies, timeout)) {
if (flashdebug)
printk("FlashWrite: Retrying write (addr=0x%X)...\n",
- (unsigned int) pWritePtr - FLASH_BASE);
+ pWritePtr - FLASH_BASE);
/*
* no LED == waiting
@@ -604,7 +610,7 @@ MSTATIC int write_block(unsigned long p, const char *buf, int count)
goto WriteRetry;
} else {
printk("Timeout in flash write! (addr=0x%X) Aborting...\n",
- (unsigned int) pWritePtr - FLASH_BASE);
+ pWritePtr - FLASH_BASE);
/*
* return error -2
*/
@@ -666,6 +672,10 @@ MSTATIC int __init nwflash_init(void)
if (machine_is_netwinder()) {
int id;
+ FLASH_BASE = __ioremap(DC21285_FLASH, KFLASH_SIZE4, 0);
+ if (!FLASH_BASE)
+ goto out;
+
id = get_flash_id();
printk("Flash ROM driver v.%s, flash device ID 0x%04X, size %d Mb.\n",
NWFLASH_VERSION, id, gbFlashSize / (1024 * 1024));
@@ -674,13 +684,14 @@ MSTATIC int __init nwflash_init(void)
ret = 0;
}
-
+out:
return ret;
}
MSTATIC void __exit nwflash_exit(void)
{
misc_deregister(&flash_miscdev);
+ iounmap((void *)FLASH_BASE);
}
EXPORT_NO_SYMBOLS;
diff --git a/drivers/char/pcmcia/serial_cb.c b/drivers/char/pcmcia/serial_cb.c
index 86bb70f57..f959b9c40 100644
--- a/drivers/char/pcmcia/serial_cb.c
+++ b/drivers/char/pcmcia/serial_cb.c
@@ -2,7 +2,7 @@
A driver for CardBus serial devices
- serial_cb.c 1.15 1999/11/24 02:52:06
+ serial_cb.c 1.20 2000/08/07 19:02:03
Copyright 1998, 1999 by Donald Becker and David Hinds
@@ -16,7 +16,7 @@
Donald Becker may be reached as becker@CESDIS.edu, or C/O
USRA Center of Excellence in Space Data and Information Sciences
Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
- David Hinds may be reached at dhinds@pcmcia.sourceforge.org
+ David Hinds may be reached at dahinds@users.sourceforge.net
======================================================================*/
@@ -39,7 +39,7 @@ static int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version =
-"serial_cb.c 1.15 1999/11/24 02:52:06 (David Hinds)";
+"serial_cb.c 1.20 2000/08/07 19:02:03 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
@@ -134,7 +134,7 @@ err_out:
static void serial_detach(dev_node_t *node)
{
- DEBUG(0, "serial_detach(tty%02d)\n", node->minor - 0x40);
+ DEBUG(0, "serial_detach(ttyS%02d)\n", node->minor - 0x40);
unregister_serial(node->minor - 0x40);
kfree(node);
MOD_DEC_USE_COUNT;
diff --git a/drivers/char/pcmcia/serial_cs.c b/drivers/char/pcmcia/serial_cs.c
index 55442dd33..af25aa9e9 100644
--- a/drivers/char/pcmcia/serial_cs.c
+++ b/drivers/char/pcmcia/serial_cs.c
@@ -2,7 +2,7 @@
A driver for PCMCIA serial devices
- serial_cs.c 1.118 2000/05/04 01:29:47
+ serial_cs.c 1.123 2000/08/24 18:46:38
The contents of this file are subject to the Mozilla Public
License Version 1.1 (the "License"); you may not use this file
@@ -15,7 +15,7 @@
rights and limitations under the License.
The initial developer of the original code is David A. Hinds
- <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds
+ <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
Alternatively, the contents of this file may be used under the
@@ -58,7 +58,7 @@ static int pc_debug = PCMCIA_DEBUG;
MODULE_PARM(pc_debug, "i");
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char *version =
-"serial_cs.c 1.118 2000/05/04 01:29:47 (David Hinds)";
+"serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)";
#else
#define DEBUG(n, args...)
#endif
@@ -242,12 +242,11 @@ static int setup_serial(serial_info_t *info, ioaddr_t port, int irq)
memset(&serial, 0, sizeof(serial));
serial.port = port;
serial.irq = irq;
- serial.flags = ASYNC_SKIP_TEST;
- serial.flags |= (info->multi || info->slave) ? ASYNC_SHARE_IRQ : 0;
+ serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
line = register_serial(&serial);
if (line < 0) {
- printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04x, "
- "irq %d failed\n", serial.port, serial.irq);
+ printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx,"
+ " irq %d failed\n", (u_long)serial.port, serial.irq);
return -1;
}
@@ -290,7 +289,7 @@ static int simple_config(dev_link_t *link)
cisparse_t parse;
cistpl_cftable_entry_t *cf = &parse.cftable_entry;
config_info_t config;
- int i, j;
+ int i, j, try;
/* If the card is already configured, look up the port and irq */
i = CardServices(GetConfigurationInfo, handle, &config);
@@ -315,22 +314,26 @@ static int simple_config(dev_link_t *link)
tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
tuple.Attributes = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
- i = first_tuple(handle, &tuple, &parse);
- while (i != CS_NO_MORE_ITEMS) {
- if (i != CS_SUCCESS) goto next_entry;
- if (cf->vpp1.present & (1<<CISTPL_POWER_VNOM))
- link->conf.Vpp1 = link->conf.Vpp2 =
- cf->vpp1.param[CISTPL_POWER_VNOM]/10000;
- if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
- (cf->io.win[0].base != 0)) {
- link->conf.ConfigIndex = cf->index;
- link->io.BasePort1 = cf->io.win[0].base;
- link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
- i = CardServices(RequestIO, link->handle, &link->io);
- if (i == CS_SUCCESS) goto found_port;
+ /* Two tries: without IO aliases, then with aliases */
+ for (try = 0; try < 2; try++) {
+ i = first_tuple(handle, &tuple, &parse);
+ while (i != CS_NO_MORE_ITEMS) {
+ if (i != CS_SUCCESS) goto next_entry;
+ if (cf->vpp1.present & (1<<CISTPL_POWER_VNOM))
+ link->conf.Vpp1 = link->conf.Vpp2 =
+ cf->vpp1.param[CISTPL_POWER_VNOM]/10000;
+ if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
+ (cf->io.win[0].base != 0)) {
+ link->conf.ConfigIndex = cf->index;
+ link->io.BasePort1 = cf->io.win[0].base;
+ link->io.IOAddrLines = (try == 0) ?
+ 16 : cf->io.flags & CISTPL_IO_LINES_MASK;
+ i = CardServices(RequestIO, link->handle, &link->io);
+ if (i == CS_SUCCESS) goto found_port;
+ }
+ next_entry:
+ i = next_tuple(handle, &tuple, &parse);
}
- next_entry:
- i = next_tuple(handle, &tuple, &parse);
}
/* Second pass: try to find an entry that isn't picky about
@@ -448,6 +451,9 @@ static int multi_config(dev_link_t *link)
}
setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+ /* The Nokia cards are not really multiport cards */
+ if (info->manfid == MANFID_NOKIA)
+ return 0;
for (i = 0; i < info->multi-1; i++)
setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
@@ -518,11 +524,13 @@ void serial_config(dev_link_t *link)
(parse.funcid.func == CISTPL_FUNCID_MULTI) ||
(parse.funcid.func == CISTPL_FUNCID_SERIAL))) {
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
- if ((first_tuple(handle, &tuple, &parse) == CS_SUCCESS) &&
- (((cf->io.nwin == 1) && (cf->io.win[0].len == 16)) ||
- ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
- (cf->io.win[1].len == 8))))
- info->multi = 2;
+ if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+ if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0))
+ info->multi = cf->io.win[0].len >> 3;
+ if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
+ (cf->io.win[1].len == 8))
+ info->multi = 2;
+ }
}
if (info->multi > 1)
diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c
index cb197afc5..2b4a71546 100644
--- a/drivers/char/pcwd.c
+++ b/drivers/char/pcwd.c
@@ -564,11 +564,7 @@ static struct miscdevice temp_miscdev = {
&pcwd_fops
};
-#ifdef MODULE
-int init_module(void)
-#else
-int __init pcwatchdog_init(void)
-#endif
+static int __init pcwatchdog_init(void)
{
int i, found = 0;
spin_lock_init(&io_lock);
@@ -644,8 +640,7 @@ int __init pcwatchdog_init(void)
return 0;
}
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit pcwatchdog_exit(void)
{
/* Disable the board */
if (revision == PCWD_REVISION_C) {
@@ -658,4 +653,6 @@ void cleanup_module(void)
release_region(current_readport, (revision == PCWD_REVISION_A) ? 2 : 4);
}
-#endif
+
+module_init(pcwatchdog_init);
+module_exit(pcwatchdog_exit);
diff --git a/drivers/char/pcxx.c b/drivers/char/pcxx.c
index 7629e24ad..582503ec3 100644
--- a/drivers/char/pcxx.c
+++ b/drivers/char/pcxx.c
@@ -14,8 +14,8 @@
*
* This Driver is currently maintained by Christoph Lameter (christoph@lameter.com)
*
- * Please contact digi for support issues at digilnux@dgii.com. Some
- * information (mostly of historical interest) can be found at
+ * Please contact digi for support issues at digilnux@dgii.com.
+ * Some more information can be found at
* http://lameter.com/digi.
*
* 1.5.2 Fall 1995 Bug fixes by David Nugent
@@ -39,17 +39,13 @@
* and Xeve also.
* 1.6.2 August, 7, 2000: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* get rid of panics, release previously allocated resources
+ * 1.6.3 August, 23, 2000: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ * cleaned up wrt verify_area.
+ * Christoph Lameter: Update documentation, email addresses
+ * and URLs. Remove some obsolete code.
*
*/
-#undef SPEED_HACK
-/* If you define SPEED_HACK then you get the following Baudrate translation
- 19200 = 57600
- 38400 = 115K
- The driver supports the native 57.6K and 115K Baudrates under Linux, but
- some distributions like Slackware 3.0 don't like these high baudrates.
-*/
-
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/ioport.h>
@@ -81,7 +77,7 @@
#include <asm/bitops.h>
#include <asm/semaphore.h>
-#define VERSION "1.6.2"
+#define VERSION "1.6.3"
#include "digi.h"
#include "fep.h"
@@ -713,11 +709,10 @@ static int pcxe_write(struct tty_struct * tty, int from_user, const unsigned cha
tail &= (size - 1);
stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);
count = MIN(stlen, count);
- if (count) {
- if (verify_area(VERIFY_READ, (char*)buf, count))
- count=0;
- else copy_from_user(ch->tmp_buf, buf, count);
- }
+ if (count)
+ if (copy_from_user(ch->tmp_buf, buf, count))
+ count = 0;
+
buf = ch->tmp_buf;
memoff(ch);
restore_flags(flags);
@@ -1896,11 +1891,6 @@ fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds,
static unsigned termios2digi_c(struct channel *ch, unsigned cflag)
{
unsigned res = 0;
-#ifdef SPEED_HACK
- /* CL: HACK to force 115200 at 38400 and 57600 at 19200 Baud */
- if ((cflag & CBAUD)== B38400) cflag=cflag - B38400 + B115200;
- if ((cflag & CBAUD)== B19200) cflag=cflag - B19200 + B57600;
-#endif
if (cflag & CBAUDEX)
{
ch->digiext.digi_flags |= DIGI_FAST;
@@ -2124,7 +2114,6 @@ static void receive_data(struct channel *ch)
static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg)
{
- int error;
struct channel *ch = (struct channel *) tty->driver_data;
volatile struct board_chan *bc;
int retval;
@@ -2163,15 +2152,13 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
return 0;
case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned int *) arg);
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *)arg);
case TIOCSSOFTCAR:
{
unsigned int value;
- error = get_user( value, (unsigned int *) arg);
- if (error)
- return error;
+ if (get_user(value, (unsigned int *) arg))
+ return -EFAULT;
tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0));
}
return 0;
@@ -2199,18 +2186,16 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
if(mstat & ch->dcd)
mflag |= TIOCM_CD;
- error = put_user(mflag, (unsigned int *) arg);
- if(error)
- return error;
+ if (put_user(mflag, (unsigned int *) arg))
+ return -EFAULT;
break;
case TIOCMBIS:
case TIOCMBIC:
case TIOCMODS:
case TIOCMSET:
- error = get_user(mstat, (unsigned int *) arg);
- if(error)
- return error;
+ if (get_user(mstat, (unsigned int *) arg))
+ return -EFAULT;
mflag = 0;
if(mstat & TIOCM_DTR)
@@ -2262,10 +2247,8 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
break;
case DIGI_GETA:
- if((error=verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t))))
- return(error);
-
- copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t));
+ if (copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t)))
+ return -EFAULT;
break;
case DIGI_SETAW:
@@ -2282,10 +2265,8 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
/* Fall Thru */
case DIGI_SETA:
- if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t))))
- return(error);
-
- copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t));
+ if (copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t)))
+ return -EFAULT;
#ifdef DEBUG_IOCTL
printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags);
#endif
@@ -2319,10 +2300,8 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
memoff(ch);
restore_flags(flags);
- if((error=verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow))))
- return(error);
-
- copy_to_user((char*)arg, &dflow, sizeof(dflow));
+ if (copy_to_user((char*)arg, &dflow, sizeof(dflow)))
+ return -EFAULT;
break;
case DIGI_SETAFLOW:
@@ -2335,10 +2314,8 @@ static int pcxe_ioctl(struct tty_struct *tty, struct file * file,
stopc = ch->stopca;
}
- if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(dflow))))
- return(error);
-
- copy_from_user(&dflow, (char*)arg, sizeof(dflow));
+ if (copy_from_user(&dflow, (char*)arg, sizeof(dflow)))
+ return -EFAULT;
if(dflow.startc != startc || dflow.stopc != stopc) {
cli();
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 07877c1a7..9b85db1d6 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -39,7 +39,13 @@
* read/write read or write in current IEEE 1284 protocol
* select wait for interrupt (in readfds)
*
+ * Changes:
* Added SETTIME/GETTIME ioctl, Fred Barnes 1999.
+ *
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 2000/08/25
+ * - On error, copy_from_user and copy_to_user do not return -EFAULT,
+ * They return the positive number of bytes *not* copied due to address
+ * space errors.
*/
#include <linux/module.h>
@@ -179,7 +185,7 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
wrote = parport_write (pp->pdev->port, kbuffer, n);
- if (wrote < 0) {
+ if (wrote <= 0) {
if (!bytes_written)
bytes_written = wrote;
break;
@@ -369,19 +375,19 @@ static int pp_ioctl(struct inode *inode, struct file *file,
case PPRSTATUS:
reg = parport_read_status (port);
- return copy_to_user ((unsigned char *) arg, &reg,
- sizeof (reg));
-
+ if (copy_to_user ((unsigned char *) arg, &reg, sizeof (reg)))
+ return -EFAULT;
+ return 0;
case PPRDATA:
reg = parport_read_data (port);
- return copy_to_user ((unsigned char *) arg, &reg,
- sizeof (reg));
-
+ if (copy_to_user ((unsigned char *) arg, &reg, sizeof (reg)))
+ return -EFAULT;
+ return 0;
case PPRCONTROL:
reg = parport_read_control (port);
- return copy_to_user ((unsigned char *) arg, &reg,
- sizeof (reg));
-
+ if (copy_to_user ((unsigned char *) arg, &reg, sizeof (reg)))
+ return -EFAULT;
+ return 0;
case PPYIELD:
parport_yield_blocking (pp->pdev);
return 0;
diff --git a/drivers/char/qpmouse.c b/drivers/char/qpmouse.c
index 4db93b1fb..bba9ddd31 100644
--- a/drivers/char/qpmouse.c
+++ b/drivers/char/qpmouse.c
@@ -344,9 +344,14 @@ int __init qpmouse_init(void)
printk(KERN_INFO "82C710 type pointing device detected -- driver installed.\n");
/* printk("82C710 address = %x (should be 0x310)\n", qp_data); */
+ queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
+ if(queue==NULL)
+ {
+ printk(KERN_ERR "qpmouse: no queue memory.\n");
+ return -ENOMEM;
+ }
qp_present = 1;
misc_register(&qp_mouse);
- queue = (struct qp_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
memset(queue, 0, sizeof(*queue));
queue->head = queue->tail = 0;
init_waitqueue_head(&queue->proc_list);
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 4b1281b50..ae4f0bbd3 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -19,10 +19,10 @@
#define dprintk(x...)
-static struct block_device *raw_device_bindings[256] = {};
-static int raw_device_inuse[256] = {};
-static int raw_device_sector_size[256] = {};
-static int raw_device_sector_bits[256] = {};
+static struct block_device *raw_device_bindings[256];
+static int raw_device_inuse[256];
+static int raw_device_sector_size[256];
+static int raw_device_sector_bits[256];
static ssize_t rw_raw_dev(int rw, struct file *, char *, size_t, loff_t *);
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index af94b4b3f..3d754212e 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -218,7 +218,7 @@ int copy_to_user(void *to_user, const void *from, unsigned long len)
static inline int signal_pending(struct task_struct *p)
{
- return (p->signal & (~p->blocked != 0));
+ return (p->signal & ~p->blocked) != 0;
}
#else
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index e98d706a6..bd5b20acb 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -713,7 +713,7 @@ found:
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
BCD_TO_BIN(year); /* This should never happen... */
- if (year > 20 && year < 48) {
+ if (year >= 20 && year < 48) {
epoch = 1980;
guess = "ARC console";
} else if (year >= 48 && year < 72) {
diff --git a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c
index 813594244..9eb56403e 100644
--- a/drivers/char/sbc60xxwdt.c
+++ b/drivers/char/sbc60xxwdt.c
@@ -338,4 +338,4 @@ err_out:
}
module_init(sbc60xxwdt_init);
-module_exit(sbc60xxwdt_unload)
+module_exit(sbc60xxwdt_unload);
diff --git a/drivers/char/serial.c b/drivers/char/serial.c
index 7b11c8f84..b5492def3 100644
--- a/drivers/char/serial.c
+++ b/drivers/char/serial.c
@@ -331,6 +331,10 @@ static int serial_pci_board_idx = 0;
#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
IORESOURCE_IO)
#endif
+#ifndef IS_PCI_REGION_IOMEM
+#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \
+ IORESOURCE_MEM)
+#endif
#ifndef PCI_IRQ_RESOURCE
#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start)
#endif
@@ -4185,7 +4189,7 @@ pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable)
* This is the configuration table for all of the PCI serial boards
* which we support.
*/
-static struct pci_board pci_boards[] __initdata = {
+static struct pci_board pci_boards[] __devinitdata = {
/*
* Vendor ID, Device ID,
* Subvendor ID, Subdevice ID,
@@ -4606,9 +4610,9 @@ static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev,
num_port++;
if (first_port == -1)
first_port = i;
- } else {
- num_iomem++;
}
+ if (IS_PCI_REGION_IOMEM(dev, i))
+ num_iomem++;
}
/*
diff --git a/drivers/char/serial_amba.c b/drivers/char/serial_amba.c
new file mode 100644
index 000000000..580427f6b
--- /dev/null
+++ b/drivers/char/serial_amba.c
@@ -0,0 +1,2030 @@
+/*
+ * linux/drivers/char/serial_amba.c
+ *
+ * Driver for AMBA serial ports
+ *
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * Copyright 1999 ARM Limited
+ * Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *
+ * This is a generic driver for ARM AMBA-type serial ports. They
+ * have a lot of 16550-like features, but are not register compatable.
+ * Note that although they do have CTS, DCD and DSR inputs, they do
+ * not have an RI input, nor do they have DTR or RTS outputs. If
+ * required, these have to be supplied via some other means (eg, GPIO)
+ * and hooked into this driver.
+ *
+ * This could very easily become a generic serial driver for dumb UARTs
+ * (eg, {82,16x}50, 21285, SA1100).
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#include <asm/hardware/serial_amba.h>
+
+#define SERIAL_AMBA_NAME "ttyAM"
+#define SERIAL_AMBA_MAJOR 204
+#define SERIAL_AMBA_MINOR 16
+#define SERIAL_AMBA_NR 2
+
+#define CALLOUT_AMBA_NAME "cuaam"
+#define CALLOUT_AMBA_MAJOR 205
+#define CALLOUT_AMBA_MINOR 16
+#define CALLOUT_AMBA_NR SERIAL_AMBA_NR
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define DEBUG 0
+#define DEBUG_LEDS 0
+
+#if DEBUG_LEDS
+extern int get_leds(void);
+extern int set_leds(int);
+#endif
+
+/*
+ * Access routines for the AMBA UARTs
+ */
+#define UART_GET_INT_STATUS(p) IO_READ((p)->uart_base + AMBA_UARTIIR)
+#define UART_GET_FR(p) IO_READ((p)->uart_base + AMBA_UARTFR)
+#define UART_GET_CHAR(p) IO_READ((p)->uart_base + AMBA_UARTDR)
+#define UART_PUT_CHAR(p, c) IO_WRITE((p)->uart_base + AMBA_UARTDR, (c))
+#define UART_GET_RSR(p) IO_READ((p)->uart_base + AMBA_UARTRSR)
+#define UART_GET_CR(p) IO_READ((p)->uart_base + AMBA_UARTCR)
+#define UART_PUT_CR(p,c) IO_WRITE((p)->uart_base + AMBA_UARTCR, (c))
+#define UART_GET_LCRL(p) IO_READ((p)->uart_base + AMBA_UARTLCR_L)
+#define UART_PUT_LCRL(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_L, (c))
+#define UART_GET_LCRM(p) IO_READ((p)->uart_base + AMBA_UARTLCR_M)
+#define UART_PUT_LCRM(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_M, (c))
+#define UART_GET_LCRH(p) IO_READ((p)->uart_base + AMBA_UARTLCR_H)
+#define UART_PUT_LCRH(p,c) IO_WRITE((p)->uart_base + AMBA_UARTLCR_H, (c))
+#define UART_RX_DATA(s) (((s) & AMBA_UARTFR_RXFE) == 0)
+#define UART_TX_READY(s) (((s) & AMBA_UARTFR_TXFF) == 0)
+#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0)
+
+#define AMBA_UARTRSR_ANY (AMBA_UARTRSR_OE|AMBA_UARTRSR_BE|AMBA_UARTRSR_PE|AMBA_UARTRSR_FE)
+#define AMBA_UARTFR_MODEM_ANY (AMBA_UARTFR_DCD|AMBA_UARTFR_DSR|AMBA_UARTFR_CTS)
+
+/*
+ * Things needed by tty driver
+ */
+static struct tty_driver ambanormal_driver, ambacallout_driver;
+static int ambauart_refcount;
+static struct tty_struct *ambauart_table[SERIAL_AMBA_NR];
+static struct termios *ambauart_termios[SERIAL_AMBA_NR];
+static struct termios *ambauart_termios_locked[SERIAL_AMBA_NR];
+
+#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+/*
+ * Things needed internally to this driver
+ */
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write. We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static u_char *tmp_buf;
+static DECLARE_MUTEX(tmp_buf_sem);
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+#define AMBA_ISR_PASS_LIMIT 256
+
+#define EVT_WRITE_WAKEUP 0
+
+struct amba_icount {
+ __u32 cts;
+ __u32 dsr;
+ __u32 rng;
+ __u32 dcd;
+ __u32 rx;
+ __u32 tx;
+ __u32 frame;
+ __u32 overrun;
+ __u32 parity;
+ __u32 brk;
+ __u32 buf_overrun;
+};
+
+/*
+ * Static information about the port
+ */
+struct amba_port {
+ unsigned int uart_base;
+ unsigned int irq;
+ unsigned int uartclk;
+ unsigned int fifosize;
+ unsigned int tiocm_support;
+ void (*set_mctrl)(struct amba_port *, u_int mctrl);
+};
+
+/*
+ * This is the state information which is persistent across opens
+ */
+struct amba_state {
+ struct amba_icount icount;
+ unsigned int line;
+ unsigned int close_delay;
+ unsigned int closing_wait;
+ unsigned int custom_divisor;
+ unsigned int flags;
+ struct termios normal_termios;
+ struct termios callout_termios;
+
+ int count;
+ struct amba_info *info;
+};
+
+#define AMBA_XMIT_SIZE 1024
+/*
+ * This is the state information which is only valid when the port is open.
+ */
+struct amba_info {
+ struct amba_port *port;
+ struct amba_state *state;
+ struct tty_struct *tty;
+ unsigned char x_char;
+ unsigned char old_status;
+ unsigned char read_status_mask;
+ unsigned char ignore_status_mask;
+ struct circ_buf xmit;
+ unsigned int flags;
+#ifdef SUPPORT_SYSRQ
+ unsigned long sysrq;
+#endif
+
+ unsigned int event;
+ unsigned int timeout;
+ unsigned int lcr_h;
+ unsigned int mctrl;
+ int blocked_open;
+ pid_t session;
+ pid_t pgrp;
+
+ struct tasklet_struct tlet;
+
+ wait_queue_head_t open_wait;
+ wait_queue_head_t close_wait;
+ wait_queue_head_t delta_msr_wait;
+};
+
+#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+static struct console ambauart_cons;
+#endif
+static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios);
+static void ambauart_wait_until_sent(struct tty_struct *tty, int timeout);
+
+#if 1 //def CONFIG_SERIAL_INTEGRATOR
+static void amba_set_mctrl_null(struct amba_port *port, u_int mctrl)
+{
+}
+
+static struct amba_port amba_ports[SERIAL_AMBA_NR] = {
+ {
+ uart_base: IO_ADDRESS(INTEGRATOR_UART0_BASE),
+ irq: IRQ_UARTINT0,
+ uartclk: 14745600,
+ fifosize: 8,
+ set_mctrl: amba_set_mctrl_null,
+ },
+ {
+ uart_base: IO_ADDRESS(INTEGRATOR_UART1_BASE),
+ irq: IRQ_UARTINT1,
+ uartclk: 14745600,
+ fifosize: 8,
+ set_mctrl: amba_set_mctrl_null,
+ }
+};
+#endif
+
+static struct amba_state amba_state[SERIAL_AMBA_NR];
+
+static void ambauart_enable_rx_interrupt(struct amba_info *info)
+{
+ unsigned int cr;
+
+ cr = UART_GET_CR(info->port);
+ cr |= AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE;
+ UART_PUT_CR(info->port, cr);
+}
+
+static void ambauart_disable_rx_interrupt(struct amba_info *info)
+{
+ unsigned int cr;
+
+ cr = UART_GET_CR(info->port);
+ cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE);
+ UART_PUT_CR(info->port, cr);
+}
+
+static void ambauart_enable_tx_interrupt(struct amba_info *info)
+{
+ unsigned int cr;
+
+ cr = UART_GET_CR(info->port);
+ cr |= AMBA_UARTCR_TIE;
+ UART_PUT_CR(info->port, cr);
+}
+
+static void ambauart_disable_tx_interrupt(struct amba_info *info)
+{
+ unsigned int cr;
+
+ cr = UART_GET_CR(info->port);
+ cr &= ~AMBA_UARTCR_TIE;
+ UART_PUT_CR(info->port, cr);
+}
+
+static void ambauart_stop(struct tty_struct *tty)
+{
+ struct amba_info *info = tty->driver_data;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ ambauart_disable_tx_interrupt(info);
+ restore_flags(flags);
+}
+
+static void ambauart_start(struct tty_struct *tty)
+{
+ struct amba_info *info = tty->driver_data;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ if (info->xmit.head != info->xmit.tail
+ && info->xmit.buf)
+ ambauart_enable_tx_interrupt(info);
+ restore_flags(flags);
+}
+
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static void ambauart_event(struct amba_info *info, int event)
+{
+ info->event |= 1 << event;
+ tasklet_schedule(&info->tlet);
+}
+
+static void
+#ifdef SUPPORT_SYSRQ
+ambauart_rx_chars(struct amba_info *info, struct pt_regs *regs)
+#else
+ambauart_rx_chars(struct amba_info *info)
+#endif
+{
+ struct tty_struct *tty = info->tty;
+ unsigned int status, ch, rsr, flg, ignored = 0;
+ struct amba_icount *icount = &info->state->icount;
+ struct amba_port *port = info->port;
+
+ status = UART_GET_FR(port);
+ while (UART_RX_DATA(status)) {
+ ch = UART_GET_CHAR(port);
+
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ goto ignore_char;
+ icount->rx++;
+
+ flg = TTY_NORMAL;
+
+ /*
+ * Note that the error handling code is
+ * out of the main execution path
+ */
+ rsr = UART_GET_RSR(port);
+ if (rsr & AMBA_UARTRSR_ANY)
+ goto handle_error;
+#ifdef SUPPORT_SYSRQ
+ if (info->sysrq) {
+ if (ch && time_before(jiffies, info->sysrq)) {
+ handle_sysrq(ch, regs, NULL, NULL);
+ info->sysrq = 0;
+ goto ignore_char;
+ }
+ info->sysrq = 0;
+ }
+#endif
+ error_return:
+ *tty->flip.flag_buf_ptr++ = flg;
+ *tty->flip.char_buf_ptr++ = ch;
+ tty->flip.count++;
+ ignore_char:
+ status = UART_GET_FR(port);
+ }
+out:
+ tty_flip_buffer_push(tty);
+ return;
+
+handle_error:
+ if (rsr & AMBA_UARTRSR_BE) {
+ rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE);
+ icount->brk++;
+
+#ifdef SUPPORT_SYSRQ
+ if (info->state->line == ambauart_cons.index) {
+ if (!info->sysrq) {
+ info->sysrq = jiffies + HZ*5;
+ goto ignore_char;
+ }
+ }
+#endif
+ } else if (rsr & AMBA_UARTRSR_PE)
+ icount->parity++;
+ else if (rsr & AMBA_UARTRSR_FE)
+ icount->frame++;
+ if (rsr & AMBA_UARTRSR_OE)
+ icount->overrun++;
+
+ if (rsr & info->ignore_status_mask) {
+ if (++ignored > 100)
+ goto out;
+ goto ignore_char;
+ }
+ rsr &= info->read_status_mask;
+
+ if (rsr & AMBA_UARTRSR_BE)
+ flg = TTY_BREAK;
+ else if (rsr & AMBA_UARTRSR_PE)
+ flg = TTY_PARITY;
+ else if (rsr & AMBA_UARTRSR_FE)
+ flg = TTY_FRAME;
+
+ if (rsr & AMBA_UARTRSR_OE) {
+ /*
+ * CHECK: does overrun affect the current character?
+ * ASSUMPTION: it does not.
+ */
+ *tty->flip.flag_buf_ptr++ = flg;
+ *tty->flip.char_buf_ptr++ = ch;
+ tty->flip.count++;
+ if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ goto ignore_char;
+ ch = 0;
+ flg = TTY_OVERRUN;
+ }
+#ifdef SUPPORT_SYSRQ
+ info->sysrq = 0;
+#endif
+ goto error_return;
+}
+
+static void ambauart_tx_chars(struct amba_info *info)
+{
+ struct amba_port *port = info->port;
+ int count;
+
+ if (info->x_char) {
+ UART_PUT_CHAR(port, info->x_char);
+ info->state->icount.tx++;
+ info->x_char = 0;
+ return;
+ }
+ if (info->xmit.head == info->xmit.tail
+ || info->tty->stopped
+ || info->tty->hw_stopped) {
+ ambauart_disable_tx_interrupt(info);
+ return;
+ }
+
+ count = port->fifosize;
+ do {
+ UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]);
+ info->xmit.tail = (info->xmit.tail + 1) & (AMBA_XMIT_SIZE - 1);
+ info->state->icount.tx++;
+ if (info->xmit.head == info->xmit.tail)
+ break;
+ } while (--count > 0);
+
+ if (CIRC_CNT(info->xmit.head,
+ info->xmit.tail,
+ AMBA_XMIT_SIZE) < WAKEUP_CHARS)
+ ambauart_event(info, EVT_WRITE_WAKEUP);
+
+ if (info->xmit.head == info->xmit.tail) {
+ ambauart_disable_tx_interrupt(info);
+ }
+}
+
+static void ambauart_modem_status(struct amba_info *info)
+{
+ unsigned int status, delta;
+ struct amba_icount *icount = &info->state->icount;
+
+ status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY;
+
+ delta = status ^ info->old_status;
+ info->old_status = status;
+
+ if (!delta)
+ return;
+
+ if (delta & AMBA_UARTFR_DCD) {
+ icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+ if ((info->flags & ASYNC_HARDPPS_CD) &&
+ (status & AMBA_UARTFR_DCD)
+ hardpps();
+#endif
+ if (info->flags & ASYNC_CHECK_CD) {
+ if (status & AMBA_UARTFR_DCD)
+ wake_up_interruptible(&info->open_wait);
+ else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_CALLOUT_NOHUP))) {
+ if (info->tty)
+ tty_hangup(info->tty);
+ }
+ }
+ }
+
+ if (delta & AMBA_UARTFR_DSR)
+ icount->dsr++;
+
+ if (delta & AMBA_UARTFR_CTS) {
+ icount->cts++;
+
+ if (info->flags & ASYNC_CTS_FLOW) {
+ status &= AMBA_UARTFR_CTS;
+
+ if (info->tty->hw_stopped) {
+ if (status) {
+ info->tty->hw_stopped = 0;
+ ambauart_enable_tx_interrupt(info);
+ ambauart_event(info, EVT_WRITE_WAKEUP);
+ }
+ } else {
+ if (!status) {
+ info->tty->hw_stopped = 1;
+ ambauart_disable_tx_interrupt(info);
+ }
+ }
+ }
+ }
+ wake_up_interruptible(&info->delta_msr_wait);
+
+}
+
+static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct amba_info *info = dev_id;
+ unsigned int status, pass_counter = 0;
+
+#if DEBUG_LEDS
+ // tell the world
+ set_leds(get_leds() | RED_LED);
+#endif
+
+ status = UART_GET_INT_STATUS(info->port);
+ do {
+ /*
+ * FIXME: what about clearing the interrupts?
+ */
+
+ if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS))
+#ifdef SUPPORT_SYSRQ
+ ambauart_rx_chars(info, regs);
+#else
+ ambauart_rx_chars(info);
+#endif
+ if (status & AMBA_UARTIIR_TIS)
+ ambauart_tx_chars(info);
+ if (status & AMBA_UARTIIR_MIS)
+ ambauart_modem_status(info);
+ if (pass_counter++ > AMBA_ISR_PASS_LIMIT)
+ break;
+
+ status = UART_GET_INT_STATUS(info->port);
+ } while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS | AMBA_UARTIIR_TIS));
+
+#if DEBUG_LEDS
+ // tell the world
+ set_leds(get_leds() & ~RED_LED);
+#endif
+}
+
+static void ambauart_tasklet_action(unsigned long data)
+{
+ struct amba_info *info = (struct amba_info *)data;
+ struct tty_struct *tty;
+
+ tty = info->tty;
+ if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event))
+ return;
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+}
+
+static int ambauart_startup(struct amba_info *info)
+{
+ unsigned long flags;
+ unsigned long page;
+ int retval = 0;
+
+ page = get_zeroed_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ save_flags(flags); cli();
+
+ if (info->flags & ASYNC_INITIALIZED) {
+ free_page(page);
+ goto errout;
+ }
+
+ if (info->xmit.buf)
+ free_page(page);
+ else
+ info->xmit.buf = (unsigned char *) page;
+
+ /*
+ * Allocate the IRQ
+ */
+ retval = request_irq(info->port->irq, ambauart_int, 0, "amba", info);
+ if (retval) {
+ if (capable(CAP_SYS_ADMIN)) {
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+ retval = 0;
+ }
+ goto errout;
+ }
+
+ info->mctrl = 0;
+ if (info->tty->termios->c_cflag & CBAUD)
+ info->mctrl = TIOCM_RTS | TIOCM_DTR;
+ info->port->set_mctrl(info->port, info->mctrl);
+
+ /*
+ * initialise the old status of the modem signals
+ */
+ info->old_status = UART_GET_FR(info->port) & AMBA_UARTFR_MODEM_ANY;
+
+ /*
+ * Finally, enable interrupts
+ */
+ ambauart_enable_rx_interrupt(info);
+
+ if (info->tty)
+ clear_bit(TTY_IO_ERROR, &info->tty->flags);
+ info->xmit.head = info->xmit.tail = 0;
+
+ /*
+ * Set up the tty->alt_speed kludge
+ */
+ if (info->tty) {
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
+ }
+
+ /*
+ * and set the speed of the serial port
+ */
+ ambauart_change_speed(info, 0);
+
+ info->flags |= ASYNC_INITIALIZED;
+ restore_flags(flags);
+ return 0;
+
+errout:
+ restore_flags(flags);
+ return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void ambauart_shutdown(struct amba_info *info)
+{
+ unsigned long flags;
+
+ if (!(info->flags & ASYNC_INITIALIZED))
+ return;
+
+ save_flags(flags); cli(); /* Disable interrupts */
+
+ /*
+ * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
+ * here so the queue might never be woken up
+ */
+ wake_up_interruptible(&info->delta_msr_wait);
+
+ /*
+ * Free the IRQ
+ */
+ free_irq(info->port->irq, info);
+
+ if (info->xmit.buf) {
+ unsigned long pg = (unsigned long) info->xmit.buf;
+ info->xmit.buf = NULL;
+ free_page(pg);
+ }
+
+ /*
+ * disable all interrupts, disable the port
+ */
+ UART_PUT_CR(info->port, 0);
+
+ /* disable break condition and fifos */
+ UART_PUT_LCRH(info->port, UART_GET_LCRH(info->port) &
+ ~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN));
+
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+ info->mctrl &= ~(TIOCM_DTR|TIOCM_RTS);
+ info->port->set_mctrl(info->port, info->mctrl);
+
+ /* kill off our tasklet */
+ tasklet_kill(&info->tlet);
+ if (info->tty)
+ set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+ info->flags &= ~ASYNC_INITIALIZED;
+ restore_flags(flags);
+}
+
+static void ambauart_change_speed(struct amba_info *info, struct termios *old_termios)
+{
+ unsigned int lcr_h, baud, quot, cflag, old_cr, bits;
+ unsigned long flags;
+
+ if (!info->tty || !info->tty->termios)
+ return;
+
+ cflag = info->tty->termios->c_cflag;
+
+#if DEBUG
+ printk("ambauart_set_cflag(0x%x) called\n", cflag);
+#endif
+ /* byte size and parity */
+ switch (cflag & CSIZE) {
+ case CS5: lcr_h = AMBA_UARTLCR_H_WLEN_5; bits = 7; break;
+ case CS6: lcr_h = AMBA_UARTLCR_H_WLEN_6; bits = 8; break;
+ case CS7: lcr_h = AMBA_UARTLCR_H_WLEN_7; bits = 9; break;
+ default: lcr_h = AMBA_UARTLCR_H_WLEN_8; bits = 10; break; // CS8
+ }
+ if (cflag & CSTOPB) {
+ lcr_h |= AMBA_UARTLCR_H_STP2;
+ bits ++;
+ }
+ if (cflag & PARENB) {
+ lcr_h |= AMBA_UARTLCR_H_PEN;
+ bits++;
+ if (!(cflag & PARODD))
+ lcr_h |= AMBA_UARTLCR_H_EPS;
+ }
+ if (info->port->fifosize > 1)
+ lcr_h |= AMBA_UARTLCR_H_FEN;
+
+ do {
+ /* Determine divisor based on baud rate */
+ baud = tty_get_baud_rate(info->tty);
+ if (!baud)
+ baud = 9600;
+
+ if (baud == 38400 &&
+ ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+ quot = info->state->custom_divisor;
+ else
+ quot = (info->port->uartclk / (16 * baud)) - 1;
+
+ if (!quot && old_termios) {
+ info->tty->termios->c_cflag &= ~CBAUD;
+ info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+ old_termios = NULL;
+ }
+ } while (quot == 0 && old_termios);
+
+ /* As a last resort, if the quotient is zero, default to 9600 bps */
+ if (!quot)
+ quot = (info->port->uartclk / (16 * 9600)) - 1;
+
+ info->timeout = (info->port->fifosize * HZ * bits * quot) /
+ (info->port->uartclk / 16);
+ info->timeout += HZ/50; /* Add .02 seconds of slop */
+
+ if (cflag & CRTSCTS)
+ info->flags |= ASYNC_CTS_FLOW;
+ else
+ info->flags &= ~ASYNC_CTS_FLOW;
+ if (cflag & CLOCAL)
+ info->flags &= ~ASYNC_CHECK_CD;
+ else
+ info->flags |= ASYNC_CHECK_CD;
+
+ /*
+ * Set up parity check flag
+ */
+#define RELEVENT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+ info->read_status_mask = AMBA_UARTRSR_OE;
+ if (I_INPCK(info->tty))
+ info->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
+ if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+ info->read_status_mask |= AMBA_UARTRSR_BE;
+
+ /*
+ * Characters to ignore
+ */
+ info->ignore_status_mask = 0;
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE;
+ if (I_IGNBRK(info->tty)) {
+ info->ignore_status_mask |= AMBA_UARTRSR_BE;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns to (for real raw support).
+ */
+ if (I_IGNPAR(info->tty))
+ info->ignore_status_mask |= AMBA_UARTRSR_OE;
+ }
+
+ /* first, disable everything */
+ save_flags(flags); cli();
+ old_cr = UART_GET_CR(info->port) &= ~AMBA_UARTCR_MSIE;
+
+ if ((info->flags & ASYNC_HARDPPS_CD) ||
+ (cflag & CRTSCTS) ||
+ !(cflag & CLOCAL))
+ old_cr |= AMBA_UARTCR_MSIE;
+
+ UART_PUT_CR(info->port, 0);
+ restore_flags(flags);
+
+ /* Set baud rate */
+ UART_PUT_LCRM(info->port, ((quot & 0xf00) >> 8));
+ UART_PUT_LCRL(info->port, (quot & 0xff));
+
+ /*
+ * ----------v----------v----------v----------v-----
+ * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L
+ * ----------^----------^----------^----------^-----
+ */
+ UART_PUT_LCRH(info->port, lcr_h);
+ UART_PUT_CR(info->port, old_cr);
+}
+
+static void ambauart_put_char(struct tty_struct *tty, u_char ch)
+{
+ struct amba_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (!tty || !info->xmit.buf)
+ return;
+
+ save_flags(flags); cli();
+ if (CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE) != 0) {
+ info->xmit.buf[info->xmit.head] = ch;
+ info->xmit.head = (info->xmit.head + 1) & (AMBA_XMIT_SIZE - 1);
+ }
+ restore_flags(flags);
+}
+
+static void ambauart_flush_chars(struct tty_struct *tty)
+{
+ struct amba_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (info->xmit.head == info->xmit.tail
+ || tty->stopped
+ || tty->hw_stopped
+ || !info->xmit.buf)
+ return;
+
+ save_flags(flags); cli();
+ ambauart_enable_tx_interrupt(info);
+ restore_flags(flags);
+}
+
+static int ambauart_write(struct tty_struct *tty, int from_user,
+ const u_char * buf, int count)
+{
+ struct amba_info *info = tty->driver_data;
+ unsigned long flags;
+ int c, ret = 0;
+
+ if (!tty || !info->xmit.buf || !tmp_buf)
+ return 0;
+
+ save_flags(flags);
+ if (from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ int c1;
+ c = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ AMBA_XMIT_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!ret)
+ ret = -EFAULT;
+ break;
+ }
+ cli();
+ c1 = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ AMBA_XMIT_SIZE);
+ if (c1 < c)
+ c = c1;
+ memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+ info->xmit.head = (info->xmit.head + c) &
+ (AMBA_XMIT_SIZE - 1);
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ cli();
+ while (1) {
+ c = CIRC_SPACE_TO_END(info->xmit.head,
+ info->xmit.tail,
+ AMBA_XMIT_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+ memcpy(info->xmit.buf + info->xmit.head, buf, c);
+ info->xmit.head = (info->xmit.head + c) &
+ (AMBA_XMIT_SIZE - 1);
+ buf += c;
+ count -= c;
+ ret += c;
+ }
+ restore_flags(flags);
+ }
+ if (info->xmit.head != info->xmit.tail
+ && !tty->stopped
+ && !tty->hw_stopped)
+ ambauart_enable_tx_interrupt(info);
+ return ret;
+}
+
+static int ambauart_write_room(struct tty_struct *tty)
+{
+ struct amba_info *info = tty->driver_data;
+
+ return CIRC_SPACE(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE);
+}
+
+static int ambauart_chars_in_buffer(struct tty_struct *tty)
+{
+ struct amba_info *info = tty->driver_data;
+
+ return CIRC_CNT(info->xmit.head, info->xmit.tail, AMBA_XMIT_SIZE);
+}
+
+static void ambauart_flush_buffer(struct tty_struct *tty)
+{
+ struct amba_info *info = tty->driver_data;
+ unsigned long flags;
+
+#if DEBUG
+ printk("ambauart_flush_buffer(%d) called\n",
+ MINOR(tty->device) - tty->driver.minor_start);
+#endif
+ save_flags(flags); cli();
+ info->xmit.head = info->xmit.tail = 0;
+ restore_flags(flags);
+ wake_up_interruptible(&tty->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void ambauart_send_xchar(struct tty_struct *tty, char ch)
+{
+ struct amba_info *info = tty->driver_data;
+
+ info->x_char = ch;
+ if (ch)
+ ambauart_enable_tx_interrupt(info);
+}
+
+static void ambauart_throttle(struct tty_struct *tty)
+{
+ struct amba_info *info = tty->driver_data;
+ unsigned long flags;
+
+ if (I_IXOFF(tty))
+ ambauart_send_xchar(tty, STOP_CHAR(tty));
+
+ if (tty->termios->c_cflag & CRTSCTS) {
+ save_flags(flags); cli();
+ info->mctrl &= ~TIOCM_RTS;
+ info->port->set_mctrl(info->port, info->mctrl);
+ restore_flags(flags);
+ }
+}
+
+static void ambauart_unthrottle(struct tty_struct *tty)
+{
+ struct amba_info *info = (struct amba_info *) tty->driver_data;
+ unsigned long flags;
+
+ if (I_IXOFF(tty)) {
+ if (info->x_char)
+ info->x_char = 0;
+ else
+ ambauart_send_xchar(tty, START_CHAR(tty));
+ }
+
+ if (tty->termios->c_cflag & CRTSCTS) {
+ save_flags(flags); cli();
+ info->mctrl |= TIOCM_RTS;
+ info->port->set_mctrl(info->port, info->mctrl);
+ restore_flags(flags);
+ }
+}
+
+static int get_serial_info(struct amba_info *info, struct serial_struct *retinfo)
+{
+ struct amba_state *state = info->state;
+ struct amba_port *port = info->port;
+ struct serial_struct tmp;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = 0;
+ tmp.line = state->line;
+ tmp.port = port->uart_base;
+ if (HIGH_BITS_OFFSET)
+ tmp.port_high = port->uart_base >> HIGH_BITS_OFFSET;
+ tmp.irq = port->irq;
+ tmp.flags = 0;
+ tmp.xmit_fifo_size = port->fifosize;
+ tmp.baud_base = port->uartclk / 16;
+ tmp.close_delay = state->close_delay;
+ tmp.closing_wait = state->closing_wait;
+ tmp.custom_divisor = state->custom_divisor;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int set_serial_info(struct amba_info *info,
+ struct serial_struct *newinfo)
+{
+ struct serial_struct new_serial;
+ struct amba_state *state, old_state;
+ struct amba_port *port;
+ unsigned long new_port;
+ unsigned int i, change_irq, change_port;
+ int retval = 0;
+
+ if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
+ return -EFAULT;
+
+ state = info->state;
+ old_state = *state;
+ port = info->port;
+
+ new_port = new_serial.port;
+ if (HIGH_BITS_OFFSET)
+ new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET;
+
+ change_irq = new_serial.irq != port->irq;
+ change_port = new_port != port->uart_base;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ if (change_irq || change_port ||
+ (new_serial.baud_base != port->uartclk / 16) ||
+ (new_serial.close_delay != state->close_delay) ||
+ (new_serial.xmit_fifo_size != port->fifosize) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) !=
+ (state->flags & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ state->flags = ((state->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
+ state->custom_divisor = new_serial.custom_divisor;
+ goto check_and_exit;
+ }
+
+ if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) ||
+ (new_serial.baud_base < 9600))
+ return -EINVAL;
+
+ if (new_serial.type && change_port) {
+ for (i = 0; i < SERIAL_AMBA_NR; i++)
+ if ((port != amba_ports + i) &&
+ amba_ports[i].uart_base != new_port)
+ return -EADDRINUSE;
+ }
+
+ if ((change_port || change_irq) && (state->count > 1))
+ return -EBUSY;
+
+ /*
+ * OK, past this point, all the error checking has been done.
+ * At this point, we start making changes.....
+ */
+ port->uartclk = new_serial.baud_base * 16;
+ state->flags = ((state->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
+ info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
+ (info->flags & ASYNC_INTERNAL_FLAGS));
+ state->custom_divisor = new_serial.custom_divisor;
+ state->close_delay = new_serial.close_delay * HZ / 100;
+ state->closing_wait = new_serial.closing_wait * HZ / 100;
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ port->fifosize = new_serial.xmit_fifo_size;
+
+ if (change_port || change_irq) {
+ /*
+ * We need to shutdown the serial port at the old
+ * port/irq combination.
+ */
+ ambauart_shutdown(info);
+ port->irq = new_serial.irq;
+ port->uart_base = new_port;
+ }
+
+check_and_exit:
+ if (!port->uart_base)
+ return 0;
+ if (info->flags & ASYNC_INITIALIZED) {
+ if ((old_state.flags & ASYNC_SPD_MASK) !=
+ (state->flags & ASYNC_SPD_MASK) ||
+ (old_state.custom_divisor != state->custom_divisor)) {
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+ info->tty->alt_speed = 57600;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+ info->tty->alt_speed = 115200;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+ info->tty->alt_speed = 230400;
+ if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+ info->tty->alt_speed = 460800;
+ ambauart_change_speed(info, NULL);
+ }
+ } else
+ retval = ambauart_startup(info);
+ return retval;
+}
+
+
+/*
+ * get_lsr_info - get line status register info
+ */
+static int get_lsr_info(struct amba_info *info, unsigned int *value)
+{
+ unsigned int result, status;
+ unsigned long flags;
+
+ save_flags(flags); cli();
+ status = UART_GET_FR(info->port);
+ restore_flags(flags);
+ result = status & AMBA_UARTFR_BUSY ? TIOCSER_TEMT : 0;
+
+ /*
+ * If we're about to load something into the transmit
+ * register, we'll pretend the transmitter isn't empty to
+ * avoid a race condition (depending on when the transmit
+ * interrupt happens).
+ */
+ if (info->x_char ||
+ ((CIRC_CNT(info->xmit.head, info->xmit.tail,
+ AMBA_XMIT_SIZE) > 0) &&
+ !info->tty->stopped && !info->tty->hw_stopped))
+ result &= TIOCSER_TEMT;
+
+ return put_user(result, value);
+}
+
+static int get_modem_info(struct amba_info *info, unsigned int *value)
+{
+ unsigned int result = info->mctrl;
+ unsigned int status;
+
+ status = UART_GET_FR(info->port);
+ if (status & AMBA_UARTFR_DCD)
+ result |= TIOCM_CAR;
+ if (status & AMBA_UARTFR_DSR)
+ result |= TIOCM_DSR;
+ if (status & AMBA_UARTFR_CTS)
+ result |= TIOCM_CTS;
+
+ return put_user(result, value);
+}
+
+static int set_modem_info(struct amba_info *info, unsigned int cmd,
+ unsigned int *value)
+{
+ unsigned int arg, old;
+ unsigned long flags;
+
+ if (get_user(arg, value))
+ return -EFAULT;
+
+ old = info->mctrl;
+ switch (cmd) {
+ case TIOCMBIS:
+ info->mctrl |= arg;
+ break;
+
+ case TIOCMBIC:
+ info->mctrl &= ~arg;
+ break;
+
+ case TIOCMSET:
+ info->mctrl = arg;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ save_flags(flags); cli();
+ if (old != info->mctrl)
+ info->port->set_mctrl(info->port, info->mctrl);
+ restore_flags(flags);
+ return 0;
+}
+
+static void ambauart_break_ctl(struct tty_struct *tty, int break_state)
+{
+ struct amba_info *info = tty->driver_data;
+ unsigned long flags;
+ unsigned int lcr_h;
+
+ save_flags(flags); cli();
+ lcr_h = UART_GET_LCRH(info->port);
+ if (break_state == -1)
+ lcr_h |= AMBA_UARTLCR_H_BRK;
+ else
+ lcr_h &= ~AMBA_UARTLCR_H_BRK;
+ UART_PUT_LCRH(info->port, lcr_h);
+ restore_flags(flags);
+}
+
+static int ambauart_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct amba_info *info = tty->driver_data;
+ struct amba_icount cprev, cnow;
+ struct serial_icounter_struct icount;
+ unsigned long flags;
+
+ if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+ (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) &&
+ (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+ if (tty->flags & (1 << TTY_IO_ERROR))
+ return -EIO;
+ }
+
+ switch (cmd) {
+ case TIOCMGET:
+ return get_modem_info(info, (unsigned int *)arg);
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ return set_modem_info(info, cmd, (unsigned int *)arg);
+ case TIOCGSERIAL:
+ return get_serial_info(info,
+ (struct serial_struct *)arg);
+ case TIOCSSERIAL:
+ return set_serial_info(info,
+ (struct serial_struct *)arg);
+ case TIOCSERGETLSR: /* Get line status register */
+ return get_lsr_info(info, (unsigned int *)arg);
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ save_flags(flags); cli();
+ /* note the counters on entry */
+ cprev = info->state->icount;
+ /* Force modem status interrupts on */
+ UART_PUT_CR(info->port, UART_GET_CR(info->port) | AMBA_UARTCR_MSIE);
+ restore_flags(flags);
+ while (1) {
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ save_flags(flags); cli();
+ cnow = info->state->icount; /* atomic copy */
+ restore_flags(flags);
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+ return 0;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ save_flags(flags); cli();
+ cnow = info->state->icount;
+ restore_flags(flags);
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ return copy_to_user((void *)arg, &icount, sizeof(icount))
+ ? -EFAULT : 0;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static void ambauart_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+ struct amba_info *info = tty->driver_data;
+ unsigned long flags;
+ unsigned int cflag = tty->termios->c_cflag;
+
+ if ((cflag ^ old_termios->c_cflag) == 0 &&
+ RELEVENT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
+ return;
+
+ ambauart_change_speed(info, old_termios);
+
+ /* Handle transition to B0 status */
+ if ((old_termios->c_cflag & CBAUD) &&
+ !(cflag & CBAUD)) {
+ save_flags(flags); cli();
+ info->mctrl &= ~(TIOCM_RTS | TIOCM_DTR);
+ info->port->set_mctrl(info->port, info->mctrl);
+ restore_flags(flags);
+ }
+
+ /* Handle transition away from B0 status */
+ if (!(old_termios->c_cflag & CBAUD) &&
+ (cflag & CBAUD)) {
+ save_flags(flags); cli();
+ info->mctrl |= TIOCM_DTR;
+ if (!(cflag & CRTSCTS) ||
+ !test_bit(TTY_THROTTLED, &tty->flags))
+ info->mctrl |= TIOCM_RTS;
+ info->port->set_mctrl(info->port, info->mctrl);
+ restore_flags(flags);
+ }
+
+ /* Handle turning off CRTSCTS */
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(cflag & CRTSCTS)) {
+ tty->hw_stopped = 0;
+ ambauart_start(tty);
+ }
+
+#if 0
+ /*
+ * No need to wake up processes in open wait, since they
+ * sample the CLOCAL flag once, and don't recheck it.
+ * XXX It's not clear whether the current behavior is correct
+ * or not. Hence, this may change.....
+ */
+ if (!(old_termios->c_cflag & CLOCAL) &&
+ (tty->termios->c_cflag & CLOCAL))
+ wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+static void ambauart_close(struct tty_struct *tty, struct file *filp)
+{
+ struct amba_info *info = tty->driver_data;
+ struct amba_state *state;
+ unsigned long flags;
+
+ if (!info)
+ return;
+
+ state = info->state;
+
+#if DEBUG
+ printk("ambauart_close() called\n");
+#endif
+
+ save_flags(flags); cli();
+
+ if (tty_hung_up_p(filp)) {
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+ return;
+ }
+
+ if ((tty->count == 1) && (state->count != 1)) {
+ /*
+ * Uh, oh. tty->count is 1, which means that the tty
+ * structure will be freed. state->count should always
+ * be one in these conditions. If it's greater than
+ * one, we've got real problems, since it means the
+ * serial port won't be shutdown.
+ */
+ printk("ambauart_close: bad serial port count; tty->count is 1, "
+ "state->count is %d\n", state->count);
+ state->count = 1;
+ }
+ if (--state->count < 0) {
+ printk("rs_close: bad serial port count for %s%d: %d\n",
+ tty->driver.name, info->state->line, state->count);
+ state->count = 0;
+ }
+ if (state->count) {
+ MOD_DEC_USE_COUNT;
+ restore_flags(flags);
+ return;
+ }
+ info->flags |= ASYNC_CLOSING;
+ restore_flags(flags);
+ /*
+ * Save the termios structure, since this port may have
+ * separate termios for callout and dialin.
+ */
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ info->state->normal_termios = *tty->termios;
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ info->state->callout_termios = *tty->termios;
+ /*
+ * Now we wait for the transmit buffer to clear; and we notify
+ * the line discipline to only process XON/XOFF characters.
+ */
+ tty->closing = 1;
+ if (info->state->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+ tty_wait_until_sent(tty, info->state->closing_wait);
+ /*
+ * At this point, we stop accepting input. To do this, we
+ * disable the receive line status interrupts.
+ */
+ if (info->flags & ASYNC_INITIALIZED) {
+ ambauart_disable_rx_interrupt(info);
+ /*
+ * Before we drop DTR, make sure the UART transmitter
+ * has completely drained; this is especially
+ * important if there is a transmit FIFO!
+ */
+ ambauart_wait_until_sent(tty, info->timeout);
+ }
+ ambauart_shutdown(info);
+ if (tty->driver.flush_buffer)
+ tty->driver.flush_buffer(tty);
+ if (tty->ldisc.flush_buffer)
+ tty->ldisc.flush_buffer(tty);
+ tty->closing = 0;
+ info->event = 0;
+ info->tty = NULL;
+ if (info->blocked_open) {
+ if (info->state->close_delay) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(info->state->close_delay);
+ }
+ wake_up_interruptible(&info->open_wait);
+ }
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+ ASYNC_CLOSING);
+ wake_up_interruptible(&info->close_wait);
+ MOD_DEC_USE_COUNT;
+}
+
+static void ambauart_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ struct amba_info *info = (struct amba_info *) tty->driver_data;
+ unsigned long char_time, expire;
+ unsigned int status;
+
+ if (info->port->fifosize == 0)
+ return;
+
+ /*
+ * Set the check interval to be 1/5 of the estimated time to
+ * send a single character, and make it at least 1. The check
+ * interval should also be less than the timeout.
+ *
+ * Note: we have to use pretty tight timings here to satisfy
+ * the NIST-PCTS.
+ */
+ char_time = (info->timeout - HZ/50) / info->port->fifosize;
+ char_time = char_time / 5;
+ if (char_time == 0)
+ char_time = 1;
+ if (timeout && timeout < char_time)
+ char_time = timeout;
+ /*
+ * If the transmitter hasn't cleared in twice the approximate
+ * amount of time to send the entire FIFO, it probably won't
+ * ever clear. This assumes the UART isn't doing flow
+ * control, which is currently the case. Hence, if it ever
+ * takes longer than info->timeout, this is probably due to a
+ * UART bug of some kind. So, we clamp the timeout parameter at
+ * 2*info->timeout.
+ */
+ if (!timeout || timeout > 2 * info->timeout)
+ timeout = 2 * info->timeout;
+
+ expire = jiffies + timeout;
+#if DEBUG
+ printk("ambauart_wait_until_sent(%d), jiff=%lu, expire=%lu...\n",
+ MINOR(tty->device) - tty->driver.minor_start, jiffies,
+ expire);
+#endif
+ while (UART_GET_FR(info->port) & AMBA_UARTFR_BUSY) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(char_time);
+ if (signal_pending(current))
+ break;
+ if (timeout && time_after(jiffies, expire))
+ break;
+ status = UART_GET_FR(info->port);
+ }
+ set_current_state(TASK_RUNNING);
+}
+
+static void ambauart_hangup(struct tty_struct *tty)
+{
+ struct amba_info *info = tty->driver_data;
+ struct amba_state *state = info->state;
+
+ ambauart_flush_buffer(tty);
+ if (info->flags & ASYNC_CLOSING)
+ return;
+ ambauart_shutdown(info);
+ info->event = 0;
+ state->count = 0;
+ info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+ info->tty = NULL;
+ wake_up_interruptible(&info->open_wait);
+}
+
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
+ struct amba_info *info)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct amba_state *state = info->state;
+ unsigned long flags;
+ int do_clocal = 0, extra_count = 0, retval;
+
+ /*
+ * If the device is in the middle of being closed, then block
+ * until it's done, and then try again.
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+ return (info->flags & ASYNC_HUP_NOTIFY) ?
+ -EAGAIN : -ERESTARTSYS;
+ }
+
+ /*
+ * If this is a callout device, then just make sure the normal
+ * device isn't being used.
+ */
+ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+ if (info->flags & ASYNC_NORMAL_ACTIVE)
+ return -EBUSY;
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_SESSION_LOCKOUT) &&
+ (info->session != current->session))
+ return -EBUSY;
+ if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (info->flags & ASYNC_PGRP_LOCKOUT) &&
+ (info->pgrp != current->pgrp))
+ return -EBUSY;
+ info->flags |= ASYNC_CALLOUT_ACTIVE;
+ return 0;
+ }
+
+ /*
+ * If non-blocking mode is set, or the port is not enabled,
+ * then make the check up front and then exit.
+ */
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
+ if (info->flags & ASYNC_CALLOUT_ACTIVE)
+ return -EBUSY;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+ }
+
+ if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+ if (state->normal_termios.c_cflag & CLOCAL)
+ do_clocal = 1;
+ } else {
+ if (tty->termios->c_cflag & CLOCAL)
+ do_clocal = 1;
+ }
+
+ /*
+ * Block waiting for the carrier detect and the line to become
+ * free (i.e., not in use by the callout). While we are in
+ * this loop, state->count is dropped by one, so that
+ * rs_close() knows when to free things. We restore it upon
+ * exit, either normal or abnormal.
+ */
+ retval = 0;
+ add_wait_queue(&info->open_wait, &wait);
+ save_flags(flags); cli();
+ if (!tty_hung_up_p(filp)) {
+ extra_count = 1;
+ state->count--;
+ }
+ restore_flags(flags);
+ info->blocked_open++;
+ while (1) {
+ save_flags(flags); cli();
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ (tty->termios->c_cflag & CBAUD)) {
+ info->mctrl = TIOCM_DTR | TIOCM_RTS;
+ info->port->set_mctrl(info->port, info->mctrl);
+ }
+ restore_flags(flags);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp) ||
+ !(info->flags & ASYNC_INITIALIZED)) {
+ if (info->flags & ASYNC_HUP_NOTIFY)
+ retval = -EAGAIN;
+ else
+ retval = -ERESTARTSYS;
+ break;
+ }
+ if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+ !(info->flags & ASYNC_CLOSING) &&
+ (do_clocal || (UART_GET_FR(info->port) & AMBA_UARTFR_DCD)))
+ break;
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&info->open_wait, &wait);
+ if (extra_count)
+ state->count++;
+ info->blocked_open--;
+ if (retval)
+ return retval;
+ info->flags |= ASYNC_NORMAL_ACTIVE;
+ return 0;
+}
+
+static struct amba_info *ambauart_get(int line)
+{
+ struct amba_info *info;
+ struct amba_state *state = amba_state + line;
+
+ state->count++;
+ if (state->info)
+ return state->info;
+ info = kmalloc(sizeof(struct amba_info), GFP_KERNEL);
+ if (info) {
+ memset(info, 0, sizeof(struct amba_info));
+ init_waitqueue_head(&info->open_wait);
+ init_waitqueue_head(&info->close_wait);
+ init_waitqueue_head(&info->delta_msr_wait);
+ info->flags = state->flags;
+ info->state = state;
+ info->port = amba_ports + line;
+ tasklet_init(&info->tlet, ambauart_tasklet_action,
+ (unsigned long)info);
+ }
+ if (state->info) {
+ kfree(info);
+ return state->info;
+ }
+ state->info = info;
+ return info;
+}
+
+static int ambauart_open(struct tty_struct *tty, struct file *filp)
+{
+ struct amba_info *info;
+ int retval, line = MINOR(tty->device) - tty->driver.minor_start;
+
+#if DEBUG
+ printk("ambauart_open(%d) called\n", line);
+#endif
+
+ // is this a line that we've got?
+ MOD_INC_USE_COUNT;
+ if (line >= SERIAL_AMBA_NR) {
+ MOD_DEC_USE_COUNT;
+ return -ENODEV;
+ }
+
+ info = ambauart_get(line);
+ if (!info)
+ return -ENOMEM;
+
+ tty->driver_data = info;
+ info->tty = tty;
+ info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+
+ /*
+ * Make sure we have the temporary buffer allocated
+ */
+ if (!tmp_buf) {
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ if (tmp_buf)
+ free_page(page);
+ else if (!page) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+ tmp_buf = (u_char *)page;
+ }
+
+ /*
+ * If the port is in the middle of closing, bail out now.
+ */
+ if (tty_hung_up_p(filp) ||
+ (info->flags & ASYNC_CLOSING)) {
+ if (info->flags & ASYNC_CLOSING)
+ interruptible_sleep_on(&info->close_wait);
+ MOD_DEC_USE_COUNT;
+ return -EAGAIN;
+ }
+
+ /*
+ * Start up the serial port
+ */
+ retval = ambauart_startup(info);
+ if (retval) {
+ MOD_DEC_USE_COUNT;
+ return retval;
+ }
+
+ retval = block_til_ready(tty, filp, info);
+ if (retval) {
+ MOD_DEC_USE_COUNT;
+ return retval;
+ }
+
+ if ((info->state->count == 1) &&
+ (info->flags & ASYNC_SPLIT_TERMIOS)) {
+ if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+ *tty->termios = info->state->normal_termios;
+ else
+ *tty->termios = info->state->callout_termios;
+ }
+#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+ if (ambauart_cons.cflag && ambauart_cons.index == line) {
+ tty->termios->c_cflag = ambauart_cons.cflag;
+ ambauart_cons.cflag = 0;
+ }
+#endif
+ ambauart_change_speed(info, NULL);
+ info->session = current->session;
+ info->pgrp = current->pgrp;
+ return 0;
+}
+
+int __init ambauart_init(void)
+{
+ int i;
+
+ ambanormal_driver.magic = TTY_DRIVER_MAGIC;
+ ambanormal_driver.driver_name = "serial_amba";
+ ambanormal_driver.name = SERIAL_AMBA_NAME;
+ ambanormal_driver.major = SERIAL_AMBA_MAJOR;
+ ambanormal_driver.minor_start = SERIAL_AMBA_MINOR;
+ ambanormal_driver.num = SERIAL_AMBA_NR;
+ ambanormal_driver.type = TTY_DRIVER_TYPE_SERIAL;
+ ambanormal_driver.subtype = SERIAL_TYPE_NORMAL;
+ ambanormal_driver.init_termios = tty_std_termios;
+ ambanormal_driver.init_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+ ambanormal_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ ambanormal_driver.refcount = &ambauart_refcount;
+ ambanormal_driver.table = ambauart_table;
+ ambanormal_driver.termios = ambauart_termios;
+ ambanormal_driver.termios_locked = ambauart_termios_locked;
+
+ ambanormal_driver.open = ambauart_open;
+ ambanormal_driver.close = ambauart_close;
+ ambanormal_driver.write = ambauart_write;
+ ambanormal_driver.put_char = ambauart_put_char;
+ ambanormal_driver.flush_chars = ambauart_flush_chars;
+ ambanormal_driver.write_room = ambauart_write_room;
+ ambanormal_driver.chars_in_buffer = ambauart_chars_in_buffer;
+ ambanormal_driver.flush_buffer = ambauart_flush_buffer;
+ ambanormal_driver.ioctl = ambauart_ioctl;
+ ambanormal_driver.throttle = ambauart_throttle;
+ ambanormal_driver.unthrottle = ambauart_unthrottle;
+ ambanormal_driver.send_xchar = ambauart_send_xchar;
+ ambanormal_driver.set_termios = ambauart_set_termios;
+ ambanormal_driver.stop = ambauart_stop;
+ ambanormal_driver.start = ambauart_start;
+ ambanormal_driver.hangup = ambauart_hangup;
+ ambanormal_driver.break_ctl = ambauart_break_ctl;
+ ambanormal_driver.wait_until_sent = ambauart_wait_until_sent;
+ ambanormal_driver.read_proc = NULL;
+
+ /*
+ * The callout device is just like the normal device except for
+ * the major number and the subtype code.
+ */
+ ambacallout_driver = ambanormal_driver;
+ ambacallout_driver.name = CALLOUT_AMBA_NAME;
+ ambacallout_driver.major = CALLOUT_AMBA_MAJOR;
+ ambacallout_driver.subtype = SERIAL_TYPE_CALLOUT;
+ ambacallout_driver.read_proc = NULL;
+ ambacallout_driver.proc_entry = NULL;
+
+ if (tty_register_driver(&ambanormal_driver))
+ panic("Couldn't register AMBA serial driver\n");
+ if (tty_register_driver(&ambacallout_driver))
+ panic("Couldn't register AMBA callout driver\n");
+
+ for (i = 0; i < SERIAL_AMBA_NR; i++) {
+ struct amba_state *state = amba_state + i;
+ state->line = i;
+ state->close_delay = 5 * HZ / 10;
+ state->closing_wait = 30 * HZ;
+ state->callout_termios = ambacallout_driver.init_termios;
+ state->normal_termios = ambanormal_driver.init_termios;
+ }
+
+ return 0;
+}
+
+__initcall(ambauart_init);
+
+#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+/************** console driver *****************/
+
+/*
+ * This code is currently never used; console->read is never called.
+ * Therefore, although we have an implementation, we don't use it.
+ * FIXME: the "const char *s" should be fixed to "char *s" some day.
+ * (when the definition in include/linux/console.h is also fixed)
+ */
+#ifdef used_and_not_const_char_pointer
+static int ambauart_console_read(struct console *co, const char *s, u_int count)
+{
+ struct amba_port *port = &amba_ports[co->index];
+ unsigned int status;
+ char *w;
+ int c;
+#if DEBUG
+ printk("ambauart_console_read() called\n");
+#endif
+
+ c = 0;
+ w = s;
+ while (c < count) {
+ status = UART_GET_FR(port);
+ if (UART_RX_DATA(status)) {
+ *w++ = UART_GET_CHAR(port);
+ c++;
+ } else {
+ // nothing more to get, return
+ return c;
+ }
+ }
+ // return the count
+ return c;
+}
+#endif
+
+/*
+ * Print a string to the serial port trying not to disturb
+ * any possible real use of the port...
+ *
+ * The console_lock must be held when we get here.
+ */
+static void ambauart_console_write(struct console *co, const char *s, u_int count)
+{
+ struct amba_port *port = &amba_ports[co->index];
+ unsigned int status, old_cr;
+ int i;
+
+ /*
+ * First save the CR then disable the interrupts
+ */
+ old_cr = UART_GET_CR(port);
+ UART_PUT_CR(port, AMBA_UARTCR_UARTEN);
+
+ /*
+ * Now, do each character
+ */
+ for (i = 0; i < count; i++) {
+ do {
+ status = UART_GET_FR(port);
+ } while (!UART_TX_READY(status));
+ UART_PUT_CHAR(port, s[i]);
+ if (s[i] == '\n') {
+ do {
+ status = UART_GET_FR(port);
+ } while (!UART_TX_READY(status));
+ UART_PUT_CHAR(port, '\r');
+ }
+ }
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore the TCR
+ */
+ do {
+ status = UART_GET_FR(port);
+ } while (status & AMBA_UARTFR_BUSY);
+ UART_PUT_CR(port, old_cr);
+}
+
+/*
+ * Receive character from the serial port
+ */
+static int ambauart_console_wait_key(struct console *co)
+{
+ struct amba_port *port = &amba_ports[co->index];
+ unsigned int status;
+ int c;
+
+ do {
+ status = UART_GET_FR(port);
+ } while (!UART_RX_DATA(status));
+ c = UART_GET_CHAR(port);
+ return c;
+}
+
+static kdev_t ambauart_console_device(struct console *c)
+{
+ return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + c->index);
+}
+
+static int __init ambauart_console_setup(struct console *co, char *options)
+{
+ struct amba_port *port;
+ int baud = 38400;
+ int bits = 8;
+ int parity = 'n';
+ u_int cflag = CREAD | HUPCL | CLOCAL;
+ u_int lcr_h, quot;
+
+ if (co->index >= SERIAL_AMBA_NR)
+ co->index = 0;
+
+ port = &amba_ports[co->index];
+
+ if (options) {
+ char *s = options;
+ baud = simple_strtoul(s, NULL, 10);
+ while (*s >= '0' && *s <= '9')
+ s++;
+ if (*s) parity = *s++;
+ if (*s) bits = *s - '0';
+ }
+
+ /*
+ * Now construct a cflag setting.
+ */
+ switch (baud) {
+ case 1200: cflag |= B1200; break;
+ case 2400: cflag |= B2400; break;
+ case 4800: cflag |= B4800; break;
+ default: cflag |= B9600; baud = 9600; break;
+ case 19200: cflag |= B19200; break;
+ case 38400: cflag |= B38400; break;
+ case 57600: cflag |= B57600; break;
+ case 115200: cflag |= B115200; break;
+ }
+ switch (bits) {
+ case 7: cflag |= CS7; lcr_h = AMBA_UARTLCR_H_WLEN_7; break;
+ default: cflag |= CS8; lcr_h = AMBA_UARTLCR_H_WLEN_8; break;
+ }
+ switch (parity) {
+ case 'o':
+ case 'O': cflag |= PARODD; lcr_h |= AMBA_UARTLCR_H_PEN; break;
+ case 'e':
+ case 'E': cflag |= PARENB; lcr_h |= AMBA_UARTLCR_H_PEN |
+ AMBA_UARTLCR_H_EPS; break;
+ }
+
+ co->cflag = cflag;
+
+ if (port->fifosize > 1)
+ lcr_h |= AMBA_UARTLCR_H_FEN;
+
+ quot = (port->uartclk / (16 * baud)) - 1;
+
+ UART_PUT_LCRL(port, (quot & 0xff));
+ UART_PUT_LCRM(port, (quot >> 8));
+ UART_PUT_LCRH(port, lcr_h);
+
+ /* we will enable the port as we need it */
+ UART_PUT_CR(port, 0);
+
+ return 0;
+}
+
+static struct console ambauart_cons =
+{
+ name: SERIAL_AMBA_NAME,
+ write: ambauart_console_write,
+#ifdef used_and_not_const_char_pointer
+ read: ambauart_console_read,
+#endif
+ device: ambauart_console_device,
+ wait_key: ambauart_console_wait_key,
+ unblank: NULL,
+ setup: ambauart_console_setup,
+ flags: CON_PRINTBUFFER,
+ index: -1,
+};
+
+void __init ambauart_console_init(void)
+{
+ register_console(&ambauart_cons);
+}
+
+#endif /* CONFIG_SERIAL_AMBA_CONSOLE */
diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c
index 0605674e0..8f0178d9b 100644
--- a/drivers/char/sh-sci.c
+++ b/drivers/char/sh-sci.c
@@ -90,6 +90,8 @@ int sci_debug = 0;
MODULE_PARM(sci_debug, "i");
#endif
+#define dprintk(x...) do { if (sci_debug) printk(x); } while(0)
+
static void put_char(struct sci_port *port, char c)
{
unsigned long flags;
@@ -329,6 +331,9 @@ static void sci_set_baud(struct sci_port *port, int baud)
case 38400:
t = BPS_38400;
break;
+ case 57600:
+ t = BPS_57600;
+ break;
default:
printk(KERN_INFO "sci: unsupported baud rate: %d, using 115200 instead.\n", baud);
case 115200:
@@ -341,6 +346,8 @@ static void sci_set_baud(struct sci_port *port, int baud)
if(t >= 256) {
sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
t >>= 2;
+ } else {
+ sci_out(port, SCSMR, sci_in(port, SCSMR) & ~3);
}
sci_out(port, SCBRR, t);
udelay((1000000+(baud-1)) / baud); /* Wait one bit interval */
@@ -374,10 +381,9 @@ static void sci_set_termios_cflag(struct sci_port *port, int cflag, int baud)
if (cflag & CSTOPB)
smr_val |= 0x08;
sci_out(port, SCSMR, smr_val);
+ sci_set_baud(port, baud);
port->init_pins(port, cflag);
-
- sci_set_baud(port, baud);
sci_out(port, SCSCR, SCSCR_INIT(port));
}
@@ -528,13 +534,28 @@ static inline void sci_receive_chars(struct sci_port *port)
if (count == 0)
break;
- for (i=0; i<count; i++)
- tty->flip.char_buf_ptr[i] = sci_in(port, SCxRDR);
+ if (port->type == PORT_SCI) {
+ tty->flip.char_buf_ptr[0] = sci_in(port, SCxRDR);
+ tty->flip.flag_buf_ptr[0] = TTY_NORMAL;
+ } else {
+ for (i=0; i<count; i++) {
+ tty->flip.char_buf_ptr[i] = sci_in(port, SCxRDR);
+ status = sci_in(port, SCxSR);
+ if (status&SCxSR_FER(port)) {
+ tty->flip.flag_buf_ptr[i] = TTY_FRAME;
+ dprintk("sci: frame error\n");
+ } else if (status&SCxSR_PER(port)) {
+ tty->flip.flag_buf_ptr[i] = TTY_PARITY;
+ dprintk("sci: parity error\n");
+ } else {
+ tty->flip.flag_buf_ptr[i] = TTY_NORMAL;
+ }
+ }
+ }
+
sci_in(port, SCxSR); /* dummy read */
sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
- memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count);
-
/* Update the kernel buffer end */
tty->flip.count += count;
tty->flip.char_buf_ptr += count;
@@ -549,6 +570,82 @@ static inline void sci_receive_chars(struct sci_port *port)
tty_flip_buffer_push(tty);
}
+static inline int sci_handle_errors(struct sci_port *port)
+{
+ int copied = 0;
+ unsigned short status = sci_in(port, SCxSR);
+ struct tty_struct *tty = port->gs.tty;
+
+ if (status&SCxSR_ORER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
+ /* overrun error */
+ copied++;
+ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+ dprintk("sci: overrun error\n");
+ }
+
+ if (status&SCxSR_FER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
+ if (sci_rxd_in(port) == 0) {
+ /* Notify of BREAK */
+ copied++;
+ *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+ dprintk("sci: BREAK detected\n");
+ }
+ else {
+ /* frame error */
+ copied++;
+ *tty->flip.flag_buf_ptr++ = TTY_FRAME;
+ dprintk("sci: frame error\n");
+ }
+ }
+
+ if (status&SCxSR_PER(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
+ /* parity error */
+ copied++;
+ *tty->flip.flag_buf_ptr++ = TTY_PARITY;
+ dprintk("sci: parity error\n");
+ }
+
+ if (copied) {
+ tty->flip.count += copied;
+ tty_flip_buffer_push(tty);
+ }
+
+ return copied;
+}
+
+static inline int sci_handle_breaks(struct sci_port *port)
+{
+ int copied = 0;
+ unsigned short status = sci_in(port, SCxSR);
+ struct tty_struct *tty = port->gs.tty;
+
+ if (status&SCxSR_BRK(port) && tty->flip.count<TTY_FLIPBUF_SIZE) {
+ /* Notify of BREAK */
+ copied++;
+ *tty->flip.flag_buf_ptr++ = TTY_BREAK;
+ dprintk("sci: BREAK detected\n");
+ }
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7750)
+ /* XXX: Handle SCIF overrun error */
+ if (port->type == PORT_SCIF && (ctrl_inw(SCLSR2) & SCIF_ORER) != 0) {
+ ctrl_outw(0, SCLSR2);
+ if(tty->flip.count<TTY_FLIPBUF_SIZE) {
+ copied++;
+ *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+ dprintk("sci: overrun error\n");
+ }
+ }
+#endif
+
+ if (copied) {
+ tty->flip.count += copied;
+ tty_flip_buffer_push(tty);
+ }
+
+ return copied;
+}
+
static void sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
struct sci_port *port = ptr;
@@ -577,13 +674,31 @@ static void sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
struct sci_port *port = ptr;
/* Handle errors */
- if (sci_in(port, SCxSR) & SCxSR_ERRORS(port))
- sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
+ if (port->type == PORT_SCI) {
+ if(sci_handle_errors(port)) {
+ /* discard character in rx buffer */
+ sci_in(port, SCxSR);
+ sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
+ }
+ }
+ else
+ sci_rx_interrupt(irq, ptr, regs);
+
+ sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
/* Kick the transmission */
sci_tx_interrupt(irq, ptr, regs);
}
+static void sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs)
+{
+ struct sci_port *port = ptr;
+
+ /* Handle BREAKs */
+ sci_handle_breaks(port);
+ sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
+}
+
static void do_softint(void *private_)
{
struct sci_port *port = (struct sci_port *) private_;
@@ -983,8 +1098,9 @@ int __init sci_init(void)
{
struct sci_port *port;
int i, j;
- void (*handlers[3])(int irq, void *ptr, struct pt_regs *regs) = {
- sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt
+ void (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = {
+ sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
+ sci_br_interrupt,
};
printk("SuperH SCI(F) driver initialized\n");
@@ -993,7 +1109,8 @@ int __init sci_init(void)
port = &sci_ports[j];
printk("ttySC%d at 0x%08x is a %s\n", j, port->base,
(port->type == PORT_SCI) ? "SCI" : "SCIF");
- for (i=0; i<3; i++) {
+ for (i=0; i<4; i++) {
+ if (!port->irqs[i]) continue;
if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
"sci", port)) {
printk(KERN_ERR "sci: Cannot allocate irq.\n");
@@ -1001,7 +1118,6 @@ int __init sci_init(void)
}
}
}
- /* XXX: How about BRI interrupt?? */
sci_init_drivers();
diff --git a/drivers/char/sh-sci.h b/drivers/char/sh-sci.h
index c38e97c52..6f99a2b5f 100644
--- a/drivers/char/sh-sci.h
+++ b/drivers/char/sh-sci.h
@@ -20,11 +20,11 @@
#define SCIx_RXI_IRQ 1
#define SCIx_TXI_IRQ 2
-/* ERI, RXI, TXI, */
-#define SCI_IRQS { 23, 24, 25 }
-#define SH3_SCIF_IRQS { 56, 57, 59 }
-#define SH3_IRDA_IRQS { 52, 53, 55 }
-#define SH4_SCIF_IRQS { 40, 41, 43 }
+/* ERI, RXI, TXI, BRI */
+#define SCI_IRQS { 23, 24, 25, 0 }
+#define SH3_SCIF_IRQS { 56, 57, 59, 58 }
+#define SH3_IRDA_IRQS { 52, 53, 55, 54 }
+#define SH4_SCIF_IRQS { 40, 41, 43, 42 }
#if defined(CONFIG_CPU_SUBTYPE_SH7708)
# define SCI_NPORTS 1
@@ -54,6 +54,7 @@
# define SCSPTR1 0xffe0001c /* 8 bit SCI */
# define SCSPTR2 0xFFE80020 /* 16 bit SCIF */
# define SCLSR2 0xFFE80024 /* 16 bit SCIF */
+# define SCIF_ORER 0x0001 /* overrun error bit */
# 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 */ )
@@ -102,25 +103,40 @@
# define SCxSR_ERRORS(port) SCI_ERRORS
# define SCxSR_RDxF(port) SCI_RDRF
# define SCxSR_TDxE(port) SCI_TDRE
+# define SCxSR_ORER(port) SCI_ORER
+# define SCxSR_FER(port) SCI_FER
+# define SCxSR_PER(port) SCI_PER
+# define SCxSR_BRK(port) 0x00
# define SCxSR_RDxF_CLEAR(port) 0xbc
# define SCxSR_ERROR_CLEAR(port) 0xc4
# define SCxSR_TDxE_CLEAR(port) 0x78
+# define SCxSR_BREAK_CLEAR(port) 0xc4
#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_ORER(port) 0x0000
+# define SCxSR_FER(port) SCIF_FER
+# define SCxSR_PER(port) SCIF_PER
+# define SCxSR_BRK(port) SCIF_BRK
# define SCxSR_RDxF_CLEAR(port) 0x00fc
-# define SCxSR_ERROR_CLEAR(port) 0x0063
+# define SCxSR_ERROR_CLEAR(port) 0x0073
# define SCxSR_TDxE_CLEAR(port) 0x00df
+# define SCxSR_BREAK_CLEAR(port) 0x00e3
#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_ORER(port) (((port)->type == PORT_SCI) ? SCI_ORER : 0x0000)
+# define SCxSR_FER(port) (((port)->type == PORT_SCI) ? SCI_FER : SCIF_FER)
+# define SCxSR_PER(port) (((port)->type == PORT_SCI) ? SCI_PER : SCIF_PER)
+# define SCxSR_BRK(port) (((port)->type == PORT_SCI) ? 0x00 : SCIF_BRK)
# define SCxSR_RDxF_CLEAR(port) (((port)->type == PORT_SCI) ? 0xbc : 0x00fc)
-# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0063)
+# define SCxSR_ERROR_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x0073)
# define SCxSR_TDxE_CLEAR(port) (((port)->type == PORT_SCI) ? 0x78 : 0x00df)
+# define SCxSR_BREAK_CLEAR(port) (((port)->type == PORT_SCI) ? 0xc4 : 0x00e3)
#endif
/* SCFCR */
@@ -169,7 +185,7 @@ struct sci_port {
struct gs_port gs;
int type;
unsigned int base;
- unsigned char irqs[3]; /* ERI, RXI, TXI */
+ unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */
void (*init_pins)(struct sci_port* port, unsigned int cflag);
unsigned int old_cflag;
struct async_icount icount;
@@ -248,6 +264,34 @@ 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)
+#if defined(CONFIG_CPU_SUBTYPE_SH7708)
+static inline int sci_rxd_in(struct sci_port *port)
+{
+ if (port->base == 0xfffffe80)
+ return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */
+ return 1;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+static inline int sci_rxd_in(struct sci_port *port)
+{
+ if (port->base == 0xfffffe80)
+ return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCI */
+ if (port->base == 0xa4000150)
+ return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
+ if (port->base == 0xa4000140)
+ return ctrl_inb(SCPDR)&0x04 ? 1 : 0; /* IRDA */
+ return 1;
+}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
+static inline int sci_rxd_in(struct sci_port *port)
+{
+ if (port->base == 0xffe00000)
+ return ctrl_inb(SCSPTR1)&0x01 ? 1 : 0; /* SCI */
+ if (port->base == 0xffe80000)
+ return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
+ return 1;
+}
+#endif
/*
* Values for the BitRate Register (SCBRR)
@@ -289,5 +333,6 @@ SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16)
#define BPS_9600 SCBRR_VALUE(9600)
#define BPS_19200 SCBRR_VALUE(19200)
#define BPS_38400 SCBRR_VALUE(38400)
+#define BPS_57600 SCBRR_VALUE(57600)
#define BPS_115200 SCBRR_VALUE(115200)
diff --git a/drivers/char/softdog.c b/drivers/char/softdog.c
index 3d1c57907..cb508cbe2 100644
--- a/drivers/char/softdog.c
+++ b/drivers/char/softdog.c
@@ -53,7 +53,11 @@ MODULE_PARM(soft_margin,"i");
* Our timer
*/
-struct timer_list watchdog_ticktock;
+static void watchdog_fire(unsigned long);
+
+static struct timer_list watchdog_ticktock = {
+ function: watchdog_fire,
+};
static int timer_alive = 0;
@@ -164,23 +168,24 @@ static struct miscdevice softdog_miscdev=
&softdog_fops
};
-void __init watchdog_init(void)
+static int __init watchdog_init(void)
{
- misc_register(&softdog_miscdev);
- init_timer(&watchdog_ticktock);
- watchdog_ticktock.function=watchdog_fire;
+ int ret;
+
+ ret = misc_register(&softdog_miscdev);
+
+ if (ret)
+ return ret;
+
printk("Software Watchdog Timer: 0.05, timer margin: %d sec\n", soft_margin);
-}
-#ifdef MODULE
-int init_module(void)
-{
- watchdog_init();
return 0;
-}
+}
-void cleanup_module(void)
+static void __exit watchdog_exit(void)
{
misc_deregister(&softdog_miscdev);
}
-#endif
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c
new file mode 100644
index 000000000..8a92f80ac
--- /dev/null
+++ b/drivers/char/toshiba.c
@@ -0,0 +1,522 @@
+/* toshiba.c -- Linux driver for accessing the SMM on Toshiba laptops
+ *
+ * Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk)
+ *
+ * Valuable assistance and patches from:
+ * Tom May <tom@you-bastards.com>
+ * Rob Napier <rnapier@employees.org>
+ *
+ * Fn status port numbers for machine ID's courtesy of
+ * 0xfc08: Garth Berry <garth@itsbruce.net>
+ * 0xfc11: Spencer Olson <solson@novell.com>
+ * 0xfc13: Claudius Frankewitz <kryp@gmx.de>
+ * 0xfc15: Tom May <tom@you-bastards.com>
+ * 0xfc17: Dave Konrad <konrad@xenia.it>
+ * 0xfc1a: George Betzos <betzos@engr.colostate.edu>
+ * 0xfc1d: Arthur Liu <armie@slap.mine.nu>
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * This code is covered by the GNU GPL and you are free to make any
+ * changes you wish to it under the terms of the license. However the
+ * code has the potential to render your computer and/or someone else's
+ * unusable. Please proceed with care when modifying the code.
+ *
+ * Note: Unfortunately the laptop hardware can close the System Configuration
+ * Interface on it's own accord. It is therefore necessary for *all*
+ * programs using this driver to be aware that *any* SCI call can fail at
+ * *any* time. It is up to any program to be aware of this eventuality
+ * and take appropriate steps.
+ *
+ * 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, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * The information used to write this driver has been obtained by reverse
+ * engineering the software supplied by Toshiba for their portable computers in
+ * strict accordance with the European Council Directive 92/250/EEC on the legal
+ * protection of computer programs, and it's implementation into English Law by
+ * the Copyright (Computer Programs) Regulations 1992 (S.I. 1992 No.3233).
+ *
+ */
+
+#define TOSH_VERSION "1.7 22/6/2000"
+#define TOSH_DEBUG 0
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/miscdevice.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+#include <linux/proc_fs.h>
+
+#include <linux/toshiba.h>
+
+#define TOSH_MINOR_DEV 181
+
+static int tosh_id = 0x0000;
+static int tosh_bios = 0x0000;
+static int tosh_date = 0x0000;
+static int tosh_sci = 0x0000;
+static int tosh_fan = 0;
+
+static int tosh_fn = 0;
+
+MODULE_PARM(tosh_fn, "i");
+
+
+static int tosh_get_info(char *, char **, off_t, int);
+static int tosh_ioctl(struct inode *, struct file *, unsigned int,
+ unsigned long);
+
+
+static struct file_operations tosh_fops = {
+ owner: THIS_MODULE,
+ ioctl: tosh_ioctl,
+};
+
+static struct miscdevice tosh_device = {
+ TOSH_MINOR_DEV,
+ "toshiba",
+ &tosh_fops
+};
+
+/*
+ * Read the Fn key status
+ */
+static int tosh_fn_status(void)
+{
+ unsigned char scan;
+ unsigned long flags;
+
+ if (tosh_fn!=0) {
+ scan = inb(tosh_fn);
+ } else {
+ save_flags(flags);
+ cli();
+ outb(0x8e, 0xe4);
+ scan = inb(0xe5);
+ restore_flags(flags);
+ }
+
+ return (int) scan;
+}
+
+
+/*
+ * At some point we need to emulate setting the HDD auto off times for
+ * the new laptops. We can do this by calling the ide_ioctl on /dev/hda.
+ * The values we need for the various times are
+ *
+ * Disabled 0x00
+ * 1 minute 0x0c
+ * 3 minutes 0x24
+ * 5 minutes 0x3c
+ * 10 minutes 0x78
+ * 15 minutes 0xb4
+ * 20 minutes 0xf0
+ * 30 minutes 0xf1
+ *
+ */
+/*static int tosh_emulate_hdd(SMMRegisters *regs)
+{
+ return 0;
+}*/
+
+
+/*
+ * For the Portage 610CT and the Tecra 700CS/700CDT emulate the HCI fan function
+ */
+static int tosh_emulate_fan(SMMRegisters *regs)
+{
+ unsigned long eax,ecx,flags;
+ unsigned char al;
+
+ eax = regs->eax & 0xff00;
+ ecx = regs->ecx & 0xffff;
+
+ /* Portage 610CT */
+
+ if (tosh_id==0xfccb) {
+ if (eax==0xfe00) {
+ /* fan status */
+ save_flags(flags);
+ cli();
+ outb(0xbe, 0xe4);
+ al = inb(0xe5);
+ restore_flags(flags);
+ regs->eax = 0x00;
+ regs->ecx = (unsigned int) (al & 0x01);
+ }
+ if ((eax==0xff00) && (ecx==0x0000)) {
+ /* fan off */
+ save_flags(flags);
+ cli();
+ outb(0xbe, 0xe4);
+ al = inb(0xe5);
+ outb(0xbe, 0xe4);
+ outb (al | 0x01, 0xe5);
+ restore_flags(flags);
+ regs->eax = 0x00;
+ regs->ecx = 0x00;
+ }
+ if ((eax==0xff00) && (ecx==0x0001)) {
+ /* fan on */
+ save_flags(flags);
+ cli();
+ outb(0xbe, 0xe4);
+ al = inb(0xe5);
+ outb(0xbe, 0xe4);
+ outb(al & 0xfe, 0xe5);
+ restore_flags(flags);
+ regs->eax = 0x00;
+ regs->ecx = 0x01;
+ }
+ }
+
+ /* Tecra 700CS/CDT */
+
+ if (tosh_id==0xfccc) {
+ if (eax==0xfe00) {
+ /* fan status */
+ save_flags(flags);
+ cli();
+ outb(0xe0, 0xe4);
+ al = inb(0xe5);
+ restore_flags(flags);
+ regs->eax = 0x00;
+ regs->ecx = al & 0x01;
+ }
+ if ((eax==0xff00) && (ecx==0x0000)) {
+ /* fan off */
+ save_flags(flags);
+ cli();
+ outb(0xe0, 0xe4);
+ al = inb(0xe5);
+ outw(0xe0 | ((al & 0xfe) << 8), 0xe4);
+ restore_flags(flags);
+ regs->eax = 0x00;
+ regs->ecx = 0x00;
+ }
+ if ((eax==0xff00) && (ecx==0x0001)) {
+ /* fan on */
+ save_flags(flags);
+ cli();
+ outb(0xe0, 0xe4);
+ al = inb(0xe5);
+ outw(0xe0 | ((al | 0x01) << 8), 0xe4);
+ restore_flags(flags);
+ regs->eax = 0x00;
+ regs->ecx = 0x01;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * Put the laptop into System Management Mode
+ */
+static int tosh_smm(SMMRegisters *regs)
+{
+ int eax;
+
+ asm ("# load the values into the registers\n\t" \
+ "pushl %%eax\n\t" \
+ "movl 0(%%eax),%%edx\n\t" \
+ "push %%edx\n\t" \
+ "movl 4(%%eax),%%ebx\n\t" \
+ "movl 8(%%eax),%%ecx\n\t" \
+ "movl 12(%%eax),%%edx\n\t" \
+ "movl 16(%%eax),%%esi\n\t" \
+ "movl 20(%%eax),%%edi\n\t" \
+ "popl %%eax\n\t" \
+ "# call the System Management mode\n\t" \
+ "inb $0xb2,%%al\n\t"
+ "# fill out the memory with the values in the registers\n\t" \
+ "xchgl %%eax,(%%esp)\n\t"
+ "movl %%ebx,4(%%eax)\n\t" \
+ "movl %%ecx,8(%%eax)\n\t" \
+ "movl %%edx,12(%%eax)\n\t" \
+ "movl %%esi,16(%%eax)\n\t" \
+ "movl %%edi,20(%%eax)\n\t" \
+ "popl %%edx\n\t" \
+ "movl %%edx,0(%%eax)\n\t" \
+ "# setup the return value to the carry flag\n\t" \
+ "lahf\n\t" \
+ "shrl $8,%%eax\n\t" \
+ "andl $1,%%eax\n" \
+ : "=a" (eax)
+ : "a" (regs)
+ : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
+
+ return eax;
+}
+
+
+static int tosh_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
+ unsigned long arg)
+{
+ SMMRegisters regs;
+ unsigned short ax,bx;
+ int err;
+
+ if (!arg)
+ return -EINVAL;
+
+ if(copy_from_user(&regs, (SMMRegisters *) arg, sizeof(SMMRegisters)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case TOSH_SMM:
+ ax = regs.eax & 0xff00;
+ bx = regs.ebx & 0xffff;
+ /* block HCI calls to read/write memory & PCI devices */
+ if (((ax==0xff00) || (ax==0xfe00)) && (bx>0x0069))
+ return -EINVAL;
+
+ /* do we need to emulate the fan ? */
+ if (tosh_fan==1) {
+ if (((ax==0xf300) || (ax==0xf400)) && (bx==0x0004)) {
+ err = tosh_emulate_fan(&regs);
+ break;
+ }
+ }
+ err = tosh_smm(&regs);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if(copy_to_user((SMMRegisters *) arg, &regs, sizeof(SMMRegisters)))
+ return -EFAULT;
+
+ return (err==0) ? 0:-EINVAL;
+}
+
+
+/*
+ * Print the information for /proc/toshiba
+ */
+int tosh_get_info(char *buffer, char **start, off_t fpos, int length)
+{
+ char *temp;
+ int key;
+
+ temp = buffer;
+ key = tosh_fn_status();
+
+ /* Arguments
+ 0) Linux driver version (this will change if format changes)
+ 1) Machine ID
+ 2) SCI version
+ 3) BIOS version (major, minor)
+ 4) BIOS date (in SCI date format)
+ 5) Fn Key status
+ */
+
+ temp += sprintf(temp, "1.1 0x%04x %d.%d %d.%d 0x%04x 0x%02x\n",
+ tosh_id,
+ (tosh_sci & 0xff00)>>8,
+ tosh_sci & 0xff,
+ (tosh_bios & 0xff00)>>8,
+ tosh_bios & 0xff,
+ tosh_date,
+ key);
+
+ return temp-buffer;
+}
+
+
+/*
+ * Determine which port to use for the Fn key status
+ */
+static void tosh_set_fn_port(void)
+{
+ switch (tosh_id) {
+ case 0xfc11: case 0xfc13: case 0xfc15: case 0xfc1a:
+ tosh_fn = 0x62;
+ break;
+ case 0xfc08: case 0xfc17: case 0xfc1d: case 0xfcd1:
+ case 0xfce0: case 0xfce2:
+ tosh_fn = 0x68;
+ break;
+ default:
+ tosh_fn = 0x00;
+ break;
+ }
+
+ return;
+}
+
+
+/*
+ * Get the machine identification number of the current model
+ */
+static int tosh_get_machine_id(void)
+{
+ int id;
+ SMMRegisters regs;
+ unsigned short bx,cx;
+ unsigned long address;
+
+ id = (0x100*(int) isa_readb(0xffffe))+((int) isa_readb(0xffffa));
+
+ /* do we have a SCTTable machine identication number on our hands */
+
+ if (id==0xfc2f) {
+
+ /* start by getting a pointer into the BIOS */
+
+ regs.eax = 0xc000;
+ regs.ebx = 0x0000;
+ regs.ecx = 0x0000;
+ tosh_smm(&regs);
+ bx = (unsigned short) (regs.ebx & 0xffff);
+
+ /* At this point in the Toshiba routines under MS Windows
+ the bx register holds 0xe6f5. However my code is producing
+ a different value! For the time being I will just fudge the
+ value. This has been verified on a Satellite Pro 430CDT,
+ Tecra 750CDT, Tecra 780DVD and Satellite 310CDT. */
+#if TOSH_DEBUG
+ printk("toshiba: debugging ID ebx=0x%04x\n", regs.ebx);
+#endif
+ bx = 0xe6f5;
+
+ /* now twiddle with our pointer a bit */
+
+ address = 0x000f0000+bx;
+ cx = isa_readw(address);
+ address = 0x000f0009+bx+cx;
+ cx = isa_readw(address);
+ address = 0x000f000a+cx;
+ cx = isa_readw(address);
+
+ /* now construct our machine identification number */
+
+ id = ((cx & 0xff)<<8)+((cx & 0xff00)>>8);
+ }
+
+ return id;
+}
+
+
+/*
+ * Probe for the presence of a Toshiba laptop
+ *
+ * returns and non-zero if unable to detect the presence of a Toshiba
+ * laptop, otherwise zero and determines the Machine ID, BIOS version and
+ * date, and SCI version.
+ */
+int tosh_probe(void)
+{
+ int major,minor,day,year,month,flag;
+ SMMRegisters regs;
+
+ /* call the Toshiba SCI support check routine */
+
+ regs.eax = 0xf0f0;
+ regs.ebx = 0x0000;
+ regs.ecx = 0x0000;
+ flag = tosh_smm(&regs);
+
+ /* if this is not a Toshiba laptop carry flag is set and ah=0x86 */
+
+ if ((flag==1) || ((regs.eax & 0xff00)==0x8600)) {
+ printk("toshiba: not a supported Toshiba laptop\n");
+ return -ENODEV;
+ }
+
+ /* if we get this far then we are running on a Toshiba (probably)! */
+
+ tosh_sci = regs.edx & 0xffff;
+
+ /* next get the machine ID of the current laptop */
+
+ tosh_id = tosh_get_machine_id();
+
+ /* get the BIOS version */
+
+ major = isa_readb(0xfe009)-'0';
+ minor = ((isa_readb(0xfe00b)-'0')*10)+(isa_readb(0xfe00c)-'0');
+ tosh_bios = (major*0x100)+minor;
+
+ /* get the BIOS date */
+
+ day = ((isa_readb(0xffff5)-'0')*10)+(isa_readb(0xffff6)-'0');
+ month = ((isa_readb(0xffff8)-'0')*10)+(isa_readb(0xffff9)-'0');
+ year = ((isa_readb(0xffffb)-'0')*10)+(isa_readb(0xffffc)-'0');
+ tosh_date = (((year-90) & 0x1f)<<10) | ((month & 0xf)<<6)
+ | ((day & 0x1f)<<1);
+
+
+ /* in theory we should check the ports we are going to use for the
+ fn key detection (and the fan on the Portage 610/Tecra700), and
+ then request them to stop other drivers using them. However as
+ the keyboard driver grabs 0x60-0x6f and the pic driver grabs
+ 0xa0-0xbf we can't. We just have to live dangerously and use the
+ ports anyway, oh boy! */
+
+
+ /* do we need to emulate the fan? */
+
+ if ((tosh_id==0xfccb) || (tosh_id==0xfccc))
+ tosh_fan = 1;
+
+ return 0;
+}
+
+int __init tosh_init(void)
+{
+ /* are we running on a Toshiba laptop */
+
+ if (tosh_probe()!=0)
+ return -EIO;
+
+ printk(KERN_INFO "Toshiba System Managment Mode driver v"
+ TOSH_VERSION"\n");
+
+ /* set the port to use for Fn status if not specified as a parameter */
+
+ if (tosh_fn==0x00)
+ tosh_set_fn_port();
+
+ /* register the device file */
+
+ misc_register(&tosh_device);
+
+ /* register the proc entry */
+ create_proc_info_entry("toshiba", 0, NULL, tosh_get_info);
+ return 0;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+ return tosh_init();
+}
+
+void cleanup_module(void)
+{
+ /* remove the proc entry */
+ remove_proc_entry("toshiba", NULL);
+
+ /* unregister the device file */
+ misc_deregister(&tosh_device);
+}
+#endif
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 17fce4ddf..76d2df295 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -2205,6 +2205,9 @@ void __init console_init(void)
#ifdef CONFIG_ARC_CONSOLE
arc_console_init();
#endif
+#ifdef CONFIG_SERIAL_AMBA_CONSOLE
+ ambauart_console_init();
+#endif
}
static struct tty_driver dev_tty_driver, dev_syscons_driver;
diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c
index e55d94fe3..9600a5b17 100644
--- a/drivers/char/wdt.c
+++ b/drivers/char/wdt.c
@@ -26,6 +26,7 @@
* Alan Cox : Cleaned up copy/user stuff
* Tim Hockin : Added insmod parameters, comment cleanup
* Parameterized timeout
+ * Tigran Aivazian : Restructured wdt_init() to handle failures
*/
#include <linux/config.h>
@@ -49,7 +50,7 @@
#include <linux/reboot.h>
#include <linux/init.h>
-static int wdt_is_open=0;
+static int wdt_is_open;
/*
* You must set these - there is no sane way to probe for this board.
@@ -458,10 +459,6 @@ static struct notifier_block wdt_notifier=
0
};
-#ifdef MODULE
-
-#define wdt_init init_module
-
/**
* cleanup_module:
*
@@ -472,7 +469,7 @@ static struct notifier_block wdt_notifier=
* module in 60 seconds or reboot.
*/
-void cleanup_module(void)
+static void __exit wdt_exit(void)
{
misc_deregister(&wdt_miscdev);
#ifdef CONFIG_WDT_501
@@ -483,8 +480,6 @@ void cleanup_module(void)
free_irq(irq, NULL);
}
-#endif
-
/**
* wdt_init:
*
@@ -493,20 +488,58 @@ void cleanup_module(void)
* The open() function will actually kick the board off.
*/
-int __init wdt_init(void)
+static int __init wdt_init(void)
{
- printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io,irq);
- if(request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", &wdt_miscdev))
- {
- printk(KERN_ERR "IRQ %d is not free.\n", irq);
- return -EIO;
+ int ret;
+
+ ret = misc_register(&wdt_miscdev);
+ if (ret) {
+ printk(KERN_ERR "wdt: can't misc_register on minor=%d\n", WATCHDOG_MINOR);
+ goto out;
}
- misc_register(&wdt_miscdev);
-#ifdef CONFIG_WDT_501
- misc_register(&temp_miscdev);
-#endif
- request_region(io, 8, "wdt501p");
- register_reboot_notifier(&wdt_notifier);
- return 0;
+ ret = request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL);
+ if(ret) {
+ printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq);
+ goto outmisc;
+ }
+ if (!request_region(io, 8, "wdt501p")) {
+ printk(KERN_ERR "wdt: IO %X is not free.\n", io);
+ ret = -EBUSY;
+ goto outirq;
+ }
+ ret = register_reboot_notifier(&wdt_notifier);
+ if(ret) {
+ printk(KERN_ERR "wdt: can't register reboot notifier (err=%d)\n", ret);
+ goto outreg;
+ }
+
+#ifdef CONFIG_WDT_501
+ ret = misc_register(&temp_miscdev);
+ if (ret) {
+ printk(KERN_ERR "wdt: can't misc_register (temp) on minor=%d\n", TEMP_MINOR);
+ goto outrbt;
+ }
+#endif
+
+ ret = 0;
+ printk(KERN_INFO "WDT500/501-P driver 0.07 at %X (Interrupt %d)\n", io, irq);
+out:
+ return ret;
+
+#ifdef CONFIG_WDT_501
+outrbt:
+ unregister_reboot_notifier(&wdt_notifier);
+#endif
+
+outreg:
+ release_region(io,8);
+outirq:
+ free_irq(irq, NULL);
+outmisc:
+ misc_deregister(&wdt_miscdev);
+ goto out;
}
+module_init(wdt_init);
+module_exit(wdt_exit);
+
diff --git a/drivers/char/wdt285.c b/drivers/char/wdt285.c
index 6745493de..bbfb5d992 100644
--- a/drivers/char/wdt285.c
+++ b/drivers/char/wdt285.c
@@ -6,8 +6,7 @@
*
* SoftDog 0.05: A Software Watchdog Device
*
- * (c) Copyright 1996 Alan Cox <alan@cymru.net>, All Rights Reserved.
- * http://www.cymru.net
+ * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -32,7 +31,7 @@
#include <asm/uaccess.h>
#include <asm/hardware.h>
#include <asm/mach-types.h>
-#include <asm/dec21285.h>
+#include <asm/hardware/dec21285.h>
/*
* Define this to stop the watchdog actually rebooting the machine.
diff --git a/drivers/char/wdt977.c b/drivers/char/wdt977.c
index fef6bc7fc..d9ea545a7 100644
--- a/drivers/char/wdt977.c
+++ b/drivers/char/wdt977.c
@@ -24,6 +24,7 @@
#include <asm/io.h>
#include <asm/system.h>
+#include <asm/mach-types.h>
#define WATCHDOG_MINOR 130
diff --git a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c
index 8e960841b..5ff7210ae 100644
--- a/drivers/char/wdt_pci.c
+++ b/drivers/char/wdt_pci.c
@@ -29,6 +29,7 @@
* JP Nollmann : Added support for PCI wdt501p
* Alan Cox : Split ISA and PCI cards into two drivers
* Jeff Garzik : PCI cleanups
+ * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures
*/
#include <linux/config.h>
@@ -70,7 +71,7 @@
#define PCI_DEVICE_ID_WDG_CSM 0x22c0
#endif
-static int wdt_is_open=0;
+static int wdt_is_open;
/*
* You must set these - there is no sane way to probe for this board.
@@ -273,7 +274,7 @@ static ssize_t wdtpci_write(struct file *file, const char *buf, size_t count, lo
* @ptr: offset (no seek allowed)
*
* Read reports the temperature in degrees Fahrenheit. The API is in
- * farenheit. It was designed by an imperial measurement luddite.
+ * fahrenheit. It was designed by an imperial measurement luddite.
*/
static ssize_t wdtpci_read(struct file *file, char *buf, size_t count, loff_t *ptr)
@@ -499,6 +500,7 @@ static int __init wdtpci_init_one (struct pci_dev *dev,
const struct pci_device_id *ent)
{
static int dev_count = 0;
+ int ret = -EIO;
dev_count++;
if (dev_count > 1) {
@@ -513,33 +515,53 @@ static int __init wdtpci_init_one (struct pci_dev *dev,
"(Interrupt %d)\n", io, irq);
if (pci_enable_device (dev))
- goto err_out;
+ goto out;
if (request_region (io, 16, "wdt-pci") == NULL) {
printk (KERN_ERR PFX "I/O %d is not free.\n", io);
- goto err_out;
+ goto 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;
+ goto out_reg;
}
- misc_register (&wdtpci_miscdev);
+ ret = misc_register (&wdtpci_miscdev);
+ if (ret) {
+ printk (KERN_ERR PFX "can't misc_register on minor=%d\n", WATCHDOG_MINOR);
+ goto out_irq;
+ }
+ ret = register_reboot_notifier (&wdtpci_notifier);
+ if (ret) {
+ printk (KERN_ERR PFX "can't misc_register on minor=%d\n", WATCHDOG_MINOR);
+ goto out_misc;
+ }
#ifdef CONFIG_WDT_501
- misc_register (&temp_miscdev);
+ ret = misc_register (&temp_miscdev);
+ if (ret) {
+ printk (KERN_ERR PFX "can't misc_register (temp) on minor=%d\n", TEMP_MINOR);
+ goto out_rbt;
+ }
#endif
- register_reboot_notifier (&wdtpci_notifier);
-
- return 0;
+ ret = 0;
+out:
+ return ret;
-err_out_free_res:
+#ifdef CONFIG_WDT_501
+out_rbt:
+ unregister_reboot_notifier(&wdtpci_notifier);
+#endif
+out_misc:
+ misc_deregister(&wdtpci_miscdev);
+out_irq:
+ free_irq(irq, &wdtpci_miscdev);
+out_reg:
release_region (io, 16);
-err_out:
- return -EIO;
+ goto out;
}