colinux64/patch/video-core.diff
2025-02-13 19:44:47 -07:00

617 lines
18 KiB
Diff
Executable File

Index: linux-2.6.22-source/drivers/video/covideo.c
===================================================================
--- /dev/null
+++ linux-2.6.22-source/drivers/video/covideo.c
@@ -0,0 +1,589 @@
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+#include <linux/cooperative.h>
+#include <linux/cooperative_internal.h>
+#include <linux/cooperative_pci.h>
+
+#include <linux/covideo.h>
+
+#include <stdarg.h>
+
+MODULE_AUTHOR("Steve Shoecraft <sshoecraft@earthlink.net>");
+MODULE_DESCRIPTION("Cooperative Linux Video Driver");
+MODULE_LICENSE("GPL");
+
+#define COVIDEO_DEBUG 0
+#define COVIDEO_MEMTEST 0
+
+#if COVIDEO_DEBUG
+#define dprintk(m) printk m
+#else
+#define dprintk(m) /* noop */
+#endif
+
+/* Our info */
+struct covideo_par {
+ int unit;
+ void *buffer;
+ int size;
+ struct pci_dev *pdev;
+ struct mutex open_lock;
+};
+typedef struct covideo_par covideo_par_t;
+
+static void uprintk(int unit, char *fmt, ...) {
+ char line[1024],*p;
+ va_list ap;
+
+ sprintf(line,"covideo%d: ", unit);
+ p = line + strlen(line);
+
+ va_start(ap,fmt);
+ vsprintf(p,fmt,ap);
+ va_end(ap);
+}
+
+static struct fb_var_screeninfo covideo_default = {
+ .xres = 640,
+ .yres = 480,
+ .xres_virtual = 640,
+ .yres_virtual = 480,
+ .bits_per_pixel = 8,
+ .red = { 0, 8, 0 },
+ .green = { 0, 8, 0 },
+ .blue = { 0, 8, 0 },
+ .activate = FB_ACTIVATE_TEST,
+ .height = -1,
+ .width = -1,
+ .pixclock = 20000,
+ .left_margin = 64,
+ .right_margin = 64,
+ .upper_margin = 32,
+ .lower_margin = 32,
+ .hsync_len = 64,
+ .vsync_len = 2,
+ .vmode = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo covideo_fix = {
+ .id = "CoVideo",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_PSEUDOCOLOR,
+ .xpanstep = 1,
+ .ypanstep = 1,
+ .ywrapstep = 1,
+ .accel = FB_ACCEL_NONE,
+};
+
+static int covideo_open(struct fb_info *info, int user)
+{
+ covideo_par_t *par = info->par;
+
+ printk(KERN_INFO "covideo%d: open: user: %d\n", par->unit, user);
+ return 0;
+}
+
+static int covideo_release(struct fb_info *info, int user)
+{
+ covideo_par_t *par = info->par;
+
+ printk(KERN_INFO "covideo%d: close: user: %d\n", par->unit, user);
+ return 0;
+}
+
+static u_long get_line_length(int xres_virtual, int bpp)
+{
+ u_long length;
+
+ length = xres_virtual * bpp;
+ length = (length + 31) & ~31;
+ length >>= 3;
+ return (length);
+}
+
+static int covideo_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct covideo_par *par = info->par;
+ u_long line_length;
+
+// uprintk("checking var...\n");
+
+// printk("check_var: xres: %d, yres: %d, bpp: %d\n", var->xres, var->yres, var->bits_per_pixel);
+
+ /* We only do 32 BPP */
+// if (var->bits_per_pixel != 32) return -EINVAL;
+
+ /*
+ * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
+ * as FB_VMODE_SMOOTH_XPAN is only used internally
+ */
+ if (var->vmode & FB_VMODE_CONUPDATE) {
+ var->vmode |= FB_VMODE_YWRAP;
+ var->xoffset = info->var.xoffset;
+ var->yoffset = info->var.yoffset;
+ }
+
+ /*
+ * Some very basic checks
+ */
+ if (!var->xres)
+ var->xres = 1;
+ if (!var->yres)
+ var->yres = 1;
+ if (var->xres > var->xres_virtual)
+ var->xres_virtual = var->xres;
+ if (var->yres > var->yres_virtual)
+ var->yres_virtual = var->yres;
+ if (var->bits_per_pixel <= 1)
+ var->bits_per_pixel = 1;
+ else if (var->bits_per_pixel <= 8)
+ var->bits_per_pixel = 8;
+ else if (var->bits_per_pixel <= 16)
+ var->bits_per_pixel = 16;
+ else if (var->bits_per_pixel <= 24)
+ var->bits_per_pixel = 24;
+ else if (var->bits_per_pixel <= 32)
+ var->bits_per_pixel = 32;
+ else
+ return -EINVAL;
+
+ if (var->xres_virtual < var->xoffset + var->xres)
+ var->xres_virtual = var->xoffset + var->xres;
+ if (var->yres_virtual < var->yoffset + var->yres)
+ var->yres_virtual = var->yoffset + var->yres;
+
+ line_length =
+ get_line_length(var->xres_virtual, var->bits_per_pixel);
+ if (line_length * var->yres_virtual > par->size)
+ return -ENOMEM;
+
+ /*
+ * Now that we checked it we alter var. The reason being is that the video
+ * mode passed in might not work but slight changes to it might make it
+ * work. This way we let the user know what is acceptable.
+ */
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 8:
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 16: /* RGBA 5551 */
+ if (var->transp.length) {
+ var->red.offset = 0;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 10;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
+ } else { /* RGB 565 */
+ var->red.offset = 0;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 11;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ }
+ break;
+ case 24: /* RGB 888 */
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 32: /* RGBA 8888 */
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ break;
+ }
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+
+ return 0;
+}
+
+static int covideo_set_par(struct fb_info *info)
+{
+// struct covideo_par *par = info->par;
+
+// uprintk(par->unit, "setting par...\n");
+
+ printk("set_par: xres: %d, yres: %d, bpp: %d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel);
+ info->fix.line_length = get_line_length(info->var.xres_virtual, info->var.bits_per_pixel);
+ return 0;
+}
+
+static int covideo_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
+{
+ struct covideo_par *par = info->par;
+
+ uprintk(par->unit, "setting coloreg...\n");
+
+ if (regno >= 256) /* no. of hw registers */
+ return 1;
+ /*
+ * Program hardware... do anything you want with transp
+ */
+
+ /* grayscale works only partially under directcolor */
+ if (info->var.grayscale) {
+ /* grayscale = 0.30*R + 0.59*G + 0.11*B */
+ red = green = blue =
+ (red * 77 + green * 151 + blue * 28) >> 8;
+ }
+
+ /* Directcolor:
+ * var->{color}.offset contains start of bitfield
+ * var->{color}.length contains length of bitfield
+ * {hardwarespecific} contains width of RAMDAC
+ * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset)
+ * RAMDAC[X] is programmed to (red, green, blue)
+ *
+ * Pseudocolor:
+ * uses offset = 0 && length = RAMDAC register width.
+ * var->{color}.offset is 0
+ * var->{color}.length contains widht of DAC
+ * cmap is not used
+ * RAMDAC[X] is programmed to (red, green, blue)
+ * Truecolor:
+ * does not use DAC. Usually 3 are present.
+ * var->{color}.offset contains start of bitfield
+ * var->{color}.length contains length of bitfield
+ * cmap is programmed to (red << red.offset) | (green << green.offset) |
+ * (blue << blue.offset) | (transp << transp.offset)
+ * RAMDAC does not exist
+ */
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ red = CNVT_TOHW(red, info->var.red.length);
+ green = CNVT_TOHW(green, info->var.green.length);
+ blue = CNVT_TOHW(blue, info->var.blue.length);
+ transp = CNVT_TOHW(transp, info->var.transp.length);
+ break;
+ case FB_VISUAL_DIRECTCOLOR:
+ red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */
+ green = CNVT_TOHW(green, 8);
+ blue = CNVT_TOHW(blue, 8);
+ /* hey, there is bug in transp handling... */
+ transp = CNVT_TOHW(transp, 8);
+ break;
+ }
+#undef CNVT_TOHW
+ /* Truecolor has hardware independent palette */
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+ u32 v;
+
+ if (regno >= 16)
+ return 1;
+
+ v = (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset) |
+ (transp << info->var.transp.offset);
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ break;
+ case 16:
+ ((u32 *) (info->pseudo_palette))[regno] = v;
+ break;
+ case 24:
+ case 32:
+ ((u32 *) (info->pseudo_palette))[regno] = v;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int covideo_blank(int blank_mode, struct fb_info *info)
+{
+ return 0;
+}
+
+static int covideo_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ unsigned long start = vma->vm_start;
+ unsigned long size = vma->vm_end-vma->vm_start;
+ unsigned long page, pos;
+
+ if (size > info->screen_size) return -EINVAL;
+
+ pos = (unsigned long) info->screen_base;
+ while (size > 0) {
+ page = vmalloc_to_pfn((void *)pos);
+ if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
+ return -EAGAIN;
+
+ start += PAGE_SIZE;
+ pos += PAGE_SIZE;
+ if (size > PAGE_SIZE)
+ size -= PAGE_SIZE;
+ else
+ size = 0;
+ }
+
+ return 0;
+}
+
+/* Frame buffer operations */
+static struct fb_ops covideo_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = covideo_open,
+ .fb_release = covideo_release,
+ .fb_read = fb_sys_read,
+ .fb_write = fb_sys_write,
+ .fb_check_var = covideo_check_var,
+ .fb_set_par = covideo_set_par,
+ .fb_setcolreg = covideo_setcolreg,
+ .fb_blank = covideo_blank,
+ .fb_fillrect = sys_fillrect,
+ .fb_copyarea = sys_copyarea,
+ .fb_imageblit = sys_imageblit,
+ .fb_mmap = covideo_mmap,
+
+#if 0
+ /* XXX currently not implemented */
+ .fb_setcmap = covideo_setcmap,
+ .fb_pan_display = covideo_pan_display,
+ .fb_cursor = covideo_cursor,
+ .fb_rotate = covideo_rotate,
+ .fb_get_caps = svga_get_caps,
+#endif
+};
+
+#if COVIDEO_MEMTEST
+/* Simple page-level checkerboard test */
+static int test_buffer(void *buffer, int unit, int size) {
+ unsigned char *p, *t, *t0, *t1;
+ unsigned long flags;
+ int npages,rc;
+ register int i;
+
+ printk(KERN_INFO "covideo%d: testing buffer at 0x%p (size: %d)\n", unit, buffer, size);
+ rc = 1;
+ t1 = 0;
+ if ((t0 = kmalloc(PAGE_SIZE, GFP_KERNEL)) == 0) goto test_out;
+ memset(t0, 0, PAGE_SIZE);
+ if ((t1 = kmalloc(PAGE_SIZE, GFP_KERNEL)) == 0) goto test_out;
+ memset(t1, 0xFF, PAGE_SIZE);
+ npages = size >> PAGE_SHIFT;
+
+ p = buffer;
+ for(i=0; i < npages; i++) {
+ t = (i & 1 ? t1 : t0);
+ memcpy(p, t, PAGE_SIZE);
+ p += PAGE_SIZE;
+ }
+
+ co_passage_page_assert_valid();
+ co_passage_page_acquire(&flags);
+ co_passage_page->operation = CO_OPERATION_DEVICE;
+ co_passage_page->params[0] = CO_DEVICE_VIDEO;
+ co_passage_page->params[1] = CO_VIDEO_TEST;
+ co_passage_page->params[2] = unit;
+ co_switch_wrapper();
+ rc = co_passage_page->params[0];
+ co_passage_page_release(flags);
+
+ /* Fail on host side? */
+ if (rc) goto test_out;
+
+ p = buffer;
+ for(i=0; i < npages; i++) {
+ t = (i & 1 ? t0 : t1);
+ if (memcmp(p, t, PAGE_SIZE) != 0)
+ goto test_out;
+ p += PAGE_SIZE;
+ }
+
+ rc = 0;
+
+test_out:
+ if (t0) kfree(t0);
+ if (t1) kfree(t1);
+ printk(KERN_INFO "covideo%d: test %s!\n", unit, (rc ? "failed" : "passed"));
+ return rc;
+}
+#endif
+
+/*
+ * PCI Probe - probe for a single device
+*/
+static int __devinit covideo_pci_probe( struct pci_dev *pdev, const struct pci_device_id *id )
+{
+ unsigned long flags;
+ covideo_config_t *cp;
+ struct fb_info *info;
+ covideo_par_t *par;
+ void *host_buffer, *buffer;
+ u8 unit;
+ int rc, size;
+
+ /* Get our host unit */
+ pci_read_config_byte(pdev, PCI_CO_UNIT, &unit);
+
+ /* Get our config */
+ co_passage_page_assert_valid();
+ co_passage_page_acquire(&flags);
+ co_passage_page->operation = CO_OPERATION_DEVICE;
+ co_passage_page->params[0] = CO_DEVICE_VIDEO;
+ co_passage_page->params[1] = CO_VIDEO_GET_CONFIG;
+ co_passage_page->params[2] = unit;
+ co_switch_wrapper();
+ rc = co_passage_page->params[0];
+ cp = (covideo_config_t *) &co_passage_page->params[1];
+ host_buffer = cp->buffer;
+ size = cp->size;
+ co_passage_page_release(flags);
+
+ /* If unable to get size, silently skip this device */
+ if (rc) return 0;
+
+ /* Map host buffer into our space */
+ buffer = co_map_buffer(host_buffer, size);
+ if (!buffer) {
+ printk(KERN_ERR "covideo%d: unable to map video buffer!\n", unit);
+ return 0;
+ }
+
+#if COVIDEO_DEBUG
+ printk(KERN_INFO "covideo%d: buffer: %p, size: %d\n", unit, buffer, size);
+#endif
+
+#if COVIDEO_MEMTEST
+ /* Test buffer */
+ if (test_buffer(buffer, unit, size)) return -EIO;
+#endif
+
+ /* Allocate and fill driver data structure */
+ info = framebuffer_alloc(sizeof(covideo_par_t), &pdev->dev);
+ if (!info) {
+ printk(KERN_ERR "covideo%d: framebuffer alloc failed!!", unit);
+ return -ENOMEM;
+ }
+
+ /* Need to set the base and ops before find_mode */
+ info->screen_base = (char __iomem *)buffer;
+ info->screen_size = size;
+ info->fbops = &covideo_ops;
+
+#if COVIDEO_DEBUG
+ printk(KERN_INFO "covideo%d: calling find_mode...\n", unit);
+#endif
+ rc = fb_find_mode(&info->var, info, NULL, NULL, 0, NULL, 8);
+ if (!rc || (rc == 4)) info->var = covideo_default;
+
+ info->fix = covideo_fix;
+ info->fix.smem_start = (unsigned long) buffer;
+ info->fix.smem_len = size;
+ info->pseudo_palette = NULL;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ rc = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (rc < 0) goto err1;
+
+ rc = register_framebuffer(info);
+ if (rc < 0) goto err2;
+
+ par = info->par;
+ par->pdev = pdev;
+ par->unit = unit;
+ par->buffer = buffer;
+ par->size = size;
+ mutex_init(&par->open_lock);
+
+ printk(KERN_INFO "fb%d: Cooperative video at: %p, size: %dK\n", info->node,
+ buffer, size >> 10);
+
+ pci_set_drvdata(pdev, info);
+ return 0;
+
+err2:
+ fb_dealloc_cmap(&info->cmap);
+
+err1:
+ framebuffer_release(info);
+
+ return 0;
+}
+
+
+/*
+ * PCI Remove - hotplug removal
+*/
+static void __devexit covideo_pci_remove(struct pci_dev *pdev)
+{
+ pci_set_drvdata(pdev, NULL);
+}
+
+static struct pci_device_id covideo_pci_ids[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CO, PCI_DEVICE_ID_COVIDEO) },
+ { 0 }
+};
+
+static struct pci_driver covideo_pci_driver = {
+ .name = "covideo",
+ .id_table = covideo_pci_ids,
+ .probe = covideo_pci_probe,
+ .remove = __devexit_p(covideo_pci_remove),
+};
+
+extern int coio_test(void);
+
+/*
+ * PCI Init - module load
+*/
+static int __init covideo_pci_init(void) {
+#if 0
+ rc = request_irq(VIDEO_IRQ, &covideo_isr, IRQF_SAMPLE_RANDOM, "covideo", NULL);
+ if (rc) {
+ printk(KERN_ERR "covideo_pci_init: unable to get irq %d", VIDEO_IRQ);
+ return rc;
+ }
+#endif
+#if COVIDEO_DEBUG
+ printk(KERN_INFO "covideo_pci_init: registering...\n");
+#endif
+ return pci_register_driver(&covideo_pci_driver);
+}
+
+/*
+ * PCI Exit - module unload
+*/
+static void __exit covideo_pci_exit(void) {
+#if COVIDEO_DEBUG
+ printk(KERN_INFO "covideo_pci_exit: exiting\n");
+#endif
+ pci_unregister_driver(&covideo_pci_driver);
+}
+
+module_init(covideo_pci_init);
+module_exit(covideo_pci_exit);
Index: linux-2.6.22-source/include/linux/covideo.h
===================================================================
--- /dev/null
+++ linux-2.6.22-source/include/linux/covideo.h
@@ -0,0 +1,17 @@
+
+#ifndef _LINUX_COVIDEO_H_
+#define _LINUX_COVIDEO_H_
+
+enum CO_VIDEO_FUNC {
+ CO_VIDEO_GET_CONFIG,
+ CO_VIDEO_TEST,
+};
+
+struct covideo_config {
+ void *buffer;
+ int size;
+};
+
+typedef struct covideo_config covideo_config_t;
+
+#endif