diff options
Diffstat (limited to 'drivers/char')
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(¤t->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(¤t->signal, _DONT_BLOCK) && - !(sigtestsetmask(¤t->signal, _NEVER_BLOCK)) && + if (sigtestsetmask(¤t->pending.signal, _DONT_BLOCK) && + !(sigtestsetmask(¤t->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(¤t->signal, _NEVER_BLOCK))); + && !(sigtestsetmask(¤t->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(¤t->signal, _DONT_BLOCK)) { + sigtestsetmask(¤t->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(¤t->signal, _DONT_BLOCK))) { + (sigtestsetmask(¤t->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(¤t->signal, _DONT_BLOCK))) { + !(sigtestsetmask(¤t->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(¤t->signal, sig_mask)) { \ + if (sigtestsetmask(¤t->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, ®, - sizeof (reg)); - + if (copy_to_user ((unsigned char *) arg, ®, sizeof (reg))) + return -EFAULT; + return 0; case PPRDATA: reg = parport_read_data (port); - return copy_to_user ((unsigned char *) arg, ®, - sizeof (reg)); - + if (copy_to_user ((unsigned char *) arg, ®, sizeof (reg))) + return -EFAULT; + return 0; case PPRCONTROL: reg = parport_read_control (port); - return copy_to_user ((unsigned char *) arg, ®, - sizeof (reg)); - + if (copy_to_user ((unsigned char *) arg, ®, 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(®s, (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(®s); + break; + } + } + err = tosh_smm(®s); + break; + default: + return -EINVAL; + } + + if(copy_to_user((SMMRegisters *) arg, ®s, 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(®s); + 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(®s); + + /* 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; } |