All of lore.kernel.org
 help / color / mirror / Atom feed
From: ilya@theIlya.com
To: linux-mips@linux-mips.org
Cc: ralf@linux-mips.org
Subject: O2 VICE support
Date: Tue, 10 Dec 2002 11:11:20 -0800	[thread overview]
Message-ID: <20021210191120.GE609@gateway.total-knowledge.com> (raw)


[-- Attachment #1.1: Type: text/plain, Size: 135 bytes --]

Attached is patch set to add support to kernel for O2 video compression engine
(VICE). It should apply cleanly to latest CVS.

	Ilya.


[-- Attachment #1.2: vice.diff --]
[-- Type: text/plain, Size: 53234 bytes --]

Index: arch/mips64/kernel/ioctl32.c
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/ioctl32.c,v
retrieving revision 1.26
diff -u -r1.26 ioctl32.c
--- arch/mips64/kernel/ioctl32.c	12 Nov 2002 15:26:11 -0000	1.26
+++ arch/mips64/kernel/ioctl32.c	10 Dec 2002 17:02:29 -0000
@@ -55,6 +57,10 @@
 
 #include <linux/rtc.h>
 
+#ifdef CONFIG_O2_VICE
+#include <linux/vice.h>
+#endif
+
 long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
 
 static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
@@ -827,6 +968,12 @@
 COMPATIBLE_IOCTL(TIOCGSERIAL)
 COMPATIBLE_IOCTL(TIOCSSERIAL)
 COMPATIBLE_IOCTL(TIOCSERGETLSR)
+#ifdef CONFIG_O2_VICE
+COMPATIBLE_IOCTL(VICE_IOCTL_MAP_DMA)
+COMPATIBLE_IOCTL(VICE_IOCTL_MSP_RUN)
+COMPATIBLE_IOCTL(VICE_IOCTL_BSP_RUN)
+COMPATIBLE_IOCTL(VICE_IOCTL_DO_DMA)
+#endif
 
 COMPATIBLE_IOCTL(FIOCLEX)
 COMPATIBLE_IOCTL(FIONCLEX)
Index: drivers/char/Kconfig
===================================================================
RCS file: /home/cvs/linux/drivers/char/Kconfig,v
retrieving revision 1.1
diff -u -r1.1 Kconfig
--- drivers/char/Kconfig	2 Nov 2002 20:01:57 -0000	1.1
+++ drivers/char/Kconfig	10 Dec 2002 17:02:31 -0000
@@ -1281,6 +1281,8 @@
 
 source "drivers/char/pcmcia/Kconfig"
 
+source drivers/char/o2vice/Kconfig
+
 config MWAVE
 	tristate "ACP Modem (Mwave) support"
 	depends on X86
Index: drivers/char/Makefile
===================================================================
RCS file: /home/cvs/linux/drivers/char/Makefile,v
retrieving revision 1.100
diff -u -r1.100 Makefile
--- drivers/char/Makefile	12 Nov 2002 15:03:11 -0000	1.100
+++ drivers/char/Makefile	10 Dec 2002 17:02:31 -0000
@@ -111,6 +111,7 @@
 obj-$(CONFIG_AGP) += agp/
 obj-$(CONFIG_DRM) += drm/
 obj-$(CONFIG_PCMCIA) += pcmcia/
+obj-$(CONFIG_O2_VICE) += o2vice/
 
 # Files generated that shall be removed upon make clean
 clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c
--- /dev/null	Sun Jul 17 16:46:18 1994
+++ drivers/char/o2vice/Kconfig	Sat Nov  2 14:10:16 2002
@@ -0,0 +1,32 @@
+#
+# O2 VICE Engine confiuration
+#
+
+config O2_VICE
+    tristate "O2 VICE Engine Support"
+    depends on SGI_IP32
+    ---help---
+      This option enables O2 VICE Engine support.
+      VICE stands for Video Image Compression Engine. This is very powerfull
+      piece of silicon, that can greatly speed up lots of graphics, vide, or
+      sound related tasks. To be able to use it, you will also need special
+      library, that can be found at <insert URL here>
+
+config O2_VICE_DBGG
+    bool "VICE Debugger Support. READ HELP!"
+    depends on O2_VICE
+    ---help---
+      This option enables features of VICE driver needed to debug VICE library.
+      This is probably serious security risk. You don't need it. If you think
+      you do, you are wrong. Say NO.
+
+config O2_VICE_DBG
+    bool "You seem to insist... did you read help? Yes? No? READ HELP!"
+    depends on O2_VICE_DBGG
+    ---help---
+      You are still here? Didn't I just tell you that it is not needed?
+      Or do you want to say you *legally* obtained information needed for
+      programming VICE? That you got all the tools needed? As a matter of
+      fact, these tools don't even exist yet!
+
+      Sigh... You've been warned...
--- /dev/null	Sun Jul 17 16:46:18 1994
+++ drivers/char/o2vice/Makefile	Thu Sep 12 00:12:16 2002
@@ -0,0 +1,21 @@
+#
+# drivers/char/o2vice/Makefile
+#
+# Makefile for the O2 VICE Engine driver.
+#
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+#O_TARGET := vice.o
+
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+obj-$(CONFIG_O2_VICE)	+= main.o msp.o bsp.o dma.o
+#obj-$(CONFIG_O2_VICE_DBG) += vicedebug.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null	Sun Jul 17 16:46:18 1994
+++ include/linux/vice.h	Tue Dec 10 09:51:46 2002
@@ -0,0 +1,462 @@
+/*
+ * vice.h -- definitions for the SGI O2 VICE
+ *
+ * The code used as a template for 'vice' driver
+ * came from the book "Linux Device Drivers" by
+ * Alessandro Rubini and Jonathan Corbet,
+ * published by O'Reilly & Associates
+ *
+ * Copyright (C) 2002 Ilya Volynets
+ *      Development was sponsored by Total Knowledge
+ *      http://www.total-knowledge.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * =====================================================================
+ * 09.16.2002 - iluxa
+ *     - MSP and DMA units mostly work.
+ *     - Simple ioctl interface to managing I/O buffers (just 2 4M buffers)
+ */
+
+#ifndef _VICE_H_
+#define _VICE_H_
+
+#include <linux/ioctl.h> /* needed for the _IOW etc stuff used later */
+#ifdef __KERNEL__
+#include <asm/pci.h>
+#endif
+#include <linux/types.h>	/* size_t */
+
+#ifndef __KERNEL__
+typedef __u64 u64;
+typedef __u32 u32;
+typedef __u16 u16;
+#endif /* __KERNEL */
+
+/*
+ * Macros to help debugging
+ */
+
+#ifdef __KERNEL__
+
+#define VICE_DEBUG 1
+
+#undef DPRINTK             /* undef it, just in case */
+#ifdef VICE_DEBUG
+# define DPRINTK(fmt, args...) printk( KERN_DEBUG "vice: " fmt, ## args)
+#else
+# define DPRINTK(fmt, args...) /* not debugging: nothing */
+#endif
+
+#define PDEBUG DPRINTK
+
+#ifndef VICE_MAJOR
+#define VICE_MAJOR 240   /* dynamic major by default */
+#endif
+
+#define VICE_VICE 0 /* main vice device, debug, stream data through, etc. */
+
+#define VICE_MAX_TYPE 1 /* always define it to be max possible minor nr for this driver */
+
+
+#include <linux/devfs_fs_kernel.h>
+
+#include <asm/ip32/crime.h>
+
+extern devfs_handle_t vice_devfs_dir;
+/*
+ * Prototypes for shared functions
+ */
+ssize_t vice_read (struct file *filp, char *buf, size_t count,
+                    loff_t *f_pos);
+ssize_t vice_write (struct file *filp, const char *buf, size_t count,
+                     loff_t *f_pos);
+loff_t  vice_llseek (struct file *filp, loff_t off, int whence);
+int     vice_ioctl (struct inode *inode, struct file *filp,
+                     unsigned int cmd, unsigned long arg);
+#endif /* __KERNEL__ */
+
+#define VICE_MAX_DMA_BUFFERS	1024		/* Max number of VICE_PAGE_SIZE pages that can be MMAPed by userland */
+						/* Affects size of page table */
+
+#define VICE_BASE	0x17000000 		/*Physical address...*/
+#define VICE_REG(reg)	(VICE_BASE|(reg))	/*access vice register*/
+#define VICE_IO_MAX_OFFSET	0xEFFF		/* Max offset mapped to registers (TLB is *not* accessible to userspace) */
+#define VICE_MIN_OFFSET	0x10000			/* Min offset mapped to RAM */
+#define VICE_MAX_OFFSET	VICE_MIN_OFFSET+0x800000/* Max offset mapped to RAM */
+
+#ifndef BIT
+#define BIT(x)	(0x1<<x)
+#endif /* !defined BIT */
+/*
+ * VICE Register definitions
+ */
+
+#define VICE_ID		0x0008 /* VICE revision id		size 8  ro */
+#define VICE_CFG	0xE000 /* VICE config register		size 16 rw */
+#define VICE_INT_RESET	0xE008 /* VICE reset interrupt		size 9  wo */
+#define VICE_INT_EN	0xE010 /* VICE interrupt enable		size 9  rw */
+#define HST_BSP_IN_BOX	0x0028 /* Host copy of BSP/MSP inbox	size 16 ro */
+#define HST_BSP_OUT_BOX	0x0030 /* Host copy of BSP/MSP outbox	size 16 ro */
+#define MSP_CTL_STAT	0x0040 /* MSP Control/Status register	size 32 rw */
+#define MSP_EXPT_FLAG	0x0048 /* MSP Exception flag		size 32 rw */
+#define MSP_PC		0x0050 /* MSP Program Counter		size 32 rw */
+#define MSP_BAD_ADDR	0x0058 /* MSP Bad Address		size 32 ro */
+#define MSP_WATCH_POINT	0x0060 /* MSP Watch Point address	size 32 rw */
+#define MSP_EPC		0x0068 /* MSP Exception PC		size 32 ro */
+#define MSP_CAUSE	0x0070 /* MSP Exception Cause		size 32 ro */
+#define BSP_RPAGE	0x0078 /* BSP R Page			size 16 rw */
+#define BSP_SW_INT	0x0080 /* BSP Software Interrupt	size 0  wo */
+#define MSP_D_RAM	0x0100 /* MSP Data RAM Arbitration register size 32 rw */
+#define VICEMSP_COUNT	0x0108 /* MSP Free Running Counter	size 32 ro */
+#define BSP_CTL_STAT	0x0110 /* BSP Control/Status register	size 16 rw */
+#define BSP_WATCH_POINT	0x0118 /* BSP Watch Point		size 16 rw */
+#define BSP_IN_COUNT	0x0120 /* BSP Decoded Bits counter	size 24 ro */
+#define BSP_OUT_COUNT	0x0128 /* BSP Encoded Bits counter	size 24 ro */
+#define BSP_PC		0x0140 /* BSP Program Counter		size 16 rw */
+#define BSP_EPC		0x0148 /* BSP Exception PC		size 16 rw */
+#define BSP_HALT_RESET	0x0150 /* BSP Halt/Reset Register	size 2  ro */
+#define BSP_CAUSE	0x0158 /* BSP Exception Cause		size 16 ro */
+#define VICE_INT	0x0160 /* Interruot and Status		size 9  ro */
+#define BSP_FIFO_CTL_STAT 0x0168 /* BSP FIFO Control/Status	size 6  rw */
+/* 0x170, 0x178 -?? */
+#define DMA_CH1_CTL	0x0180 /* DMA Chennel 1 Control		size 16 rw */
+#define DMA_CH1_STAT	0x0188 /* DMA Channel 1 Status		size 16 ro */
+#define DMA_CH1_DATA	0x0190 /* DMA Channel 1 Fill Pattern	size 16 rw */
+#define DMA_CH1_MEM_PTR	0x0198 /* DMA Channel 1 Sys Mem Ptr	size 32 ro */
+#define DMA_CH1_VICE_PTR 0x01A0 /* DMA Channel 1 VICE Mem Ptr	size 16 ro */
+#define DMA_CH1_COUNT	0x01A8 /* DMA Channel 1 remaining count	size 16 ro */
+/*0x01B0 -- unused */
+#define MSP_SW_INT	0x01B8 /* MSP Software Interrupt	size 0  wo */
+#define DMA_CH2_CTL	0x01C0 /* DMA Chennel 2 Control		size 16 rw */
+#define DMA_CH2_STAT	0x01C8 /* DMA Channel 2 Status		size 16 ro */
+#define DMA_CH2_DATA	0x01D0 /* DMA Channel 2 Fill Pattern	size 16 rw */
+#define DMA_CH2_MEM_PTR	0x01D8 /* DMA Channel 2 Sys Mem Ptr	size 32 ro */
+#define DMA_CH2_VICE_PTR 0x01E0 /* DMA Channel 2 VICE Mem Ptr	size 16 ro */
+#define DMA_CH2_COUNT	0x01E8 /* DMA Channel 2 remaining count	size 16 ro */
+#define BSP_INBOX	0x01F0 /* BSP inbox			size 16 ro */
+#define BSP_OUTBOX	0x01F8 /* BSP outbox			size 16 rw */
+
+/* VICE RAM's */
+#define MSP_IRAM	0x2000 /* MSP instruction RAM base, length 4K */
+#define BSP_IRAM	0x4000 /* BSP instruction RAM base, length 4K */
+#define BSP_TABLE	0x5000 /* BSP Tables, length 8K */
+#define BSP_IO_IN	0x7800 /* BSP Input buffers, length 2K */
+#define BSP_IO_OUT	0x7000 /* BSP Output buffers, length 2K */
+#define VICE_DRAM_A	0x8000 /* Data RAM Bank A, , length 2K */
+#define VICE_DRAM_B	0x8800 /* Data RAM Bank B, , length 2K */
+#define VICE_DRAM_C	0x9000 /* Data RAM Bank C, , length 2K */
+
+/* VICE Interrupt status bits */
+#define VICE_INT_DMA_CH1_DONE	BIT(0)
+#define VICE_INT_DMA_CH1_ERR	BIT(1)
+#define VICE_INT_MSP_SW		BIT(2)	/* MSP wants to interrupt host (Program is finished?) */
+#define VICE_INT_MSP_ERR	BIT(3)	/* MSP exception */
+#define VICE_INT_BSP_SW		BIT(4)	/* BSP wants to interrupt host (Program is finished?) */
+#define VICE_INT_BSP_ERR	BIT(5)	/* BSP exception */
+#define VICE_INT_BUSERR		BIT(6)	/* ?? Erroneous data received through SysAD interface */
+#define VICE_INT_DMA_CH2_DONE	BIT(7)
+#define VICE_INT_DMA_CH2_ERR	BIT(8)
+
+/*
+ * VICE DMA Describtor related definitions
+ */
+
+/* Flags */
+#define VICE_DMA_HALT BIT(15)
+#define VICE_DMA_SKIP BIT(14)
+#define VICE_DMA_TOVICE  BIT(13)	/* 1=transaction is System->VICE, 0=VICE->System */
+#define VICE_DMA_FILL BIT(12)	/* 1=Pattern fill VICE memory from VICEDMA_DATA register \
+				   0=normal VICE<->System transaction */
+/* flags (11:10) */
+#define VICE_DMA_YC_NONE    (0x0<<10) /* Just plain pump it through */
+#define VICE_DMA_YC_422_420 (0x1<<10) /* Y/C 4:2:2 to Y/C 4:2:0 split */
+#define VICE_DMA_YC_422_422 (0x2<<10) /* Y/C 4:2:2 to Y/C 4:2:2 split */
+#define VICE_DMA_YC_422_Y   (0x3<<10) /* Y/C 4:2:2 to Y split -- DMA read only */
+
+/* flags(9:8) */
+#define VICE_DMA_HP_FF	(0x0<<8) /* Full Pel Vert	Full Pel Horz */
+#define VICE_DMA_HP_FH	(0x1<<8) /* Full Pel Vert	Half Pel Horz */
+#define VICE_DMA_HP_HF	(0x2<<8) /* Half Pel Vert	Full Pel Horz */
+#define VICE_DMA_HP_HH	(0x3<<8) /* Half Pel Vert	Half Pel Horz */
+
+#define VICE_DMA_ILV BIT(7) /* 0=Process describtor individually, \
+			       1=Pcocess describtors as pairs and \
+			         interleave them into VICE memory */
+/* Source/Destination location within VICE FLAGS(6:4)*/
+#define VICE_DMA_LOC_DRAMA   (0x0<<4) /* Data RAM A          */
+#define VICE_DMA_LOC_DRAMB   (0x1<<4) /* Data RAM B          */
+#define VICE_DMA_LOC_DRAMC   (0x2<<4) /* Data RAM C          */
+#define VICE_DMA_LOC_MSPI    (0x3<<4) /* MSP Instruction RAM */
+#define VICE_DMA_LOC_BSPI    (0x4<<4) /* BSP Instruction RAM */
+#define VICE_DMA_LOC_BSPTBL  (0x5<<4) /* BSP Table RAM       */
+#define VICE_DMA_LOC_BSPFIFO (0x6<<4) /* BSP Decode FIFO     */
+#define VICE_DMA_LOC_TLB     (0x7<<4) /* DMA TLB RAM         */
+
+#define VICE_DMA_HPEN BIT(3) /* 0=Half Pel mode disabled -- ignore 8:9 */
+
+typedef struct vice_dma_desc
+{
+    u64 flags;		/* See above for definitions of various bits */
+    u64 sys_addr_hi;	/* High word of system memory address */
+    u64 sys_addr_lo;	/* Low word of system memory address */
+    u64 span;		/* Length of one line */
+    u64 stride;		/* Number of bytes to skip between lines */
+    u64 line_count;	/* Number of lines */
+    u64 vice_addr_Y;	/* VICE memory address */
+    u64 vice_addr_C;	/* VICE mem address for Y/C translated mode transfers */
+} vice_dma_desc;
+
+#define DMA_DESCRIBTORS_BASE	0x1000
+#define VICE_DMA_DESC(x)	(DMA_DESCRIBTORS_BASE+((x)*sizeof(vice_dma_desc)))
+
+/*
+ * VICE DMA has eight descriptors -- 4 for each channel
+ */
+#define VICE_DMA_CH1_D1		VICE_DMA_DESC(0)
+#define VICE_DMA_CH1_D2		VICE_DMA_DESC(1)
+#define VICE_DMA_CH1_D3		VICE_DMA_DESC(2)
+#define VICE_DMA_CH1_D4		VICE_DMA_DESC(3)
+#define VICE_DMA_CH2_D1		VICE_DMA_DESC(4)
+#define VICE_DMA_CH2_D2		VICE_DMA_DESC(5)
+#define VICE_DMA_CH2_D3		VICE_DMA_DESC(6)
+#define VICE_DMA_CH2_D4		VICE_DMA_DESC(7)
+
+/* VICE DMA control register bits */
+#define VICE_DMA_CTL_GO		BIT(0) /* Write 1 to kick off DMA */
+#define VICE_DMA_CTL_IE		BIT(1) /* 1=Interrupt on DMA completion, 0=No interrupt */
+#define VICE_DMA_CTL_STOP	BIT(2) /* Write 1 to stop DMA */
+#define VICE_DMA_CTL_RESET	BIT(3) /* 1=Reset DMA engine, write 0 to allow it to run again */
+#define VICE_DMA_CTL_DESC1	BIT(4) /* Start DMA with descriptor 1 */
+#define VICE_DMA_CTL_DESC2	BIT(5) /* Start DMA with descriptor 2 */
+#define VICE_DMA_CTL_DESC3	BIT(6) /* Start DMA with descriptor 3 */
+#define VICE_DMA_CTL_DESC4	BIT(7) /* Start DMA with descriptor 4 */
+#define VICE_DMA_CTL_TLB_BYPASS	BIT(8) /* Bypass TLB for this transaction */
+#define VICE_DMA_CTL_FLUSH_BUF	BIT(9) /* What the hell does this do? */
+
+/*
+ * DMA TLB definitions
+ */
+
+#define VICE_PAGE_SHIFT 16
+#define VICE_PAGE_ORDER 4
+#define VICE_PAGE_SIZE (1<<VICE_PAGE_SHIFT)
+#define VICE_PAGE_MASK 0xFFFF0000	/* VICE DMA TLB works with 64K pages aligned on 64K boundary */
+#define VICE_TLB_OFFSET 0xF000		/* Vice TLB starts here. Range is F000-FFFC */
+#define VICE_TLB_ENTRIES 64		/* Number of TLB entried in VICE */
+
+#define VICE_DMA_LINEAR	0x00800000	/* Linear access to system memory */
+#define VICE_DMA_TILED	0x10800000	/* Tiled access to system memory */
+
+/*
+ * TLB Entry format
+ */
+#define VICE_TLB_VALID		BIT(0)
+#define VICE_TLB_WRITABLE	BIT(1)
+
+/*
+ * MSP definitions
+ */
+
+#define MSP_GO	BIT(0)	/* writing MSP_GO to MSP_CTL_STAT register starts MSP */
+#define MSP_OPERATIONAL BIT(1) /* Actually you have to write 1 to take it out of reset... Ugh */
+
+/*
+ * BSP definitions
+ */
+#define BSP_OPERATIONAL     BIT(0) /* write 1 to take BSP out of reset */
+#define BSP_HALT            BIT(1) /* write 0 to start BSP, write 1 to halt it */
+#define BSP_HALT_ACK        BIT(2) /* reads as 1, when BSP recognised HALT request */
+
+#define BSP_FIFO_CTL_RESET  BIT(2)
+
+#define MAX_BSP_HALT_WAIT              10 /*max time to vait for BSP halt before reset */
+
+/*
+ * VICE IOCTL related definitions
+ */
+#define VICE_RES_STATUS_FREE		0
+#define VICE_RES_STATUS_INPROGRESS	1
+#define VICE_RES_STATUS_DONE		2
+#define VICE_RES_STATUS_ERR		3
+
+
+typedef struct dma_run
+{
+    u32 channel;
+    u32 desc;
+    u32 status;
+} dma_run;
+
+typedef struct msp_run
+{
+    u32 pc; /* PC, where MSP have finished running (either took exception, or did SW int) */
+    u32 reason; /* MSP_EXPT_CAUSE */
+    u32 status; /* Whether MSP took exception or did SW int */
+} msp_run;
+
+typedef struct bsp_run
+{
+    u32 pc;
+    u32 reason;
+    u32 status;
+} bsp_run;
+
+/* Must be written all at once. Should I make a union of it with u32? */
+typedef struct vice_tlb_entry
+{
+    u16 page_num; /* Physical 64K page number */
+    u16 flags; /* Bit 0 - valid, bit 1 writable, rest undefined */
+} vice_tlb_entry;
+
+
+#ifdef __KERNEL__
+struct vice_dev;
+
+typedef struct vice_dev {
+    char is_open;
+    struct semaphore sem;     /* mutual exclusion semaphore     */
+    devfs_handle_t handle;    /* only used if devfs is there */
+    vice_dma_desc* ch1;       /* current DMA decriptor for channel 1 */
+    vice_dma_desc* ch2;       /* current DMA decriptor for channel 2 */
+
+    u32 ch1_dma_stat;         /* Various flags related to DMA in progress */
+    u32 ch2_dma_stat;         /* Various flags related to DMA in progress */
+
+    spinlock_t dma_lock[2];   /* spinlocks for accessing dma status for 2 VICE DMA channels */
+    u32 dma_status[2];        /* status of dma channels */
+
+    dma_addr_t dma_mem[VICE_TLB_ENTRIES*2]; /* 2 sets 64*64K pages, used for DMA to/from VICE */
+    void* dma_kmem[VICE_TLB_ENTRIES*2]; /* 2 sets 64*64K pages, used for DMA to/from VICE */
+
+    /*
+    vice_page *page_table;
+    unsigned int page_cnt;
+    */
+    /* MSP stuff */
+    u32 msp_pc;			/* PC where MSP stopped (EPC) */
+    u32 msp_int_reason;		/* Reason MSP stopped */
+    u32 msp_status;		/* Free/Working/Done/Error */
+    spinlock_t msp_lock;	/* spinlock for accessing MSP status */
+
+    /* BSP stuff */
+    u32 bsp_pc;			/* PC where BSP stopped (EPC) */
+    u32 bsp_int_reason;		/* Reason BSP stopped */
+    u32 bsp_status;		/* Free/Working/Done/Error */
+    spinlock_t bsp_lock;	/* spinlock for accessing BSP status */
+} vice_dev;
+
+#endif /* __KERNEL__ */
+
+#define VICE_DMA_STAT_DATA	BIT(0)
+#define VICE_DMA_STAT_MSP_CODE	BIT(1)
+#define VICE_DMA_STAT_BSP_CODE	BIT(2)
+#define VICE_DMA_STAT_BSP_TBL	BIT(3)
+#define VICE_DMA_STAT_DIR	BIT(4)	/* 0 - to VICE, 1 to system */
+
+/*
+ * VICE ioctl commands
+ */
+#ifdef __KERNEL__
+#define VICE_IOCTL_MAGIC	0x96
+#define VICE_IOCTL_MAP_DMA	_IOR(VICE_IOCTL_MAGIC,1,unsigned long)
+#define VICE_IOCTL_MSP_RUN	_IOR(VICE_IOCTL_MAGIC,2,msp_run)
+#define VICE_IOCTL_BSP_RUN	_IOR(VICE_IOCTL_MAGIC,3,bsp_run)
+#define VICE_IOCTL_DO_DMA	_IOWR(VICE_IOCTL_MAGIC,4,dma_run)
+#else
+#define VICE_IOCTL_MAP_DMA	0x40089601
+#define VICE_IOCTL_MSP_RUN	0x400c9602
+#define VICE_IOCTL_BSP_RUN	0x400c9603
+#define VICE_IOCTL_DO_DMA	0xc00c9604
+#endif
+
+#ifdef __KERNEL__
+/* Vice wait queue */
+//Each unit has it's own wait_queue, as they might all sleep separately
+//extern wait_queue_head_t dma_wq;
+
+static inline void vice_write_reg(u32 reg,u64 value)
+{
+    *(volatile u64*)(KSEG1ADDR(VICE_REG(reg)))=value;
+}
+static inline u64 vice_read_reg(u32 reg)
+{
+    return *(volatile u64*)(KSEG1ADDR(VICE_REG(reg)));
+}
+
+static inline void vice_write_32(u32 addr,u32 value)
+{
+    *(volatile u32*)(KSEG1ADDR(VICE_REG(addr)))=value;
+}
+static inline u32 vice_read_32(u32 addr)
+{
+    return *(volatile u32*)(KSEG1ADDR(VICE_REG(addr)));
+}
+
+int vice_dma_map_set(vice_dev *vice,unsigned long set);
+
+/*
+ * Some DMA-related inline functions
+ */
+
+static inline int vice_dma_mem_init(vice_dev *vice)
+{
+    int i;
+    for (i=0; i<64*2;i++){
+	if(!(vice->dma_kmem[i]=pci_alloc_consistent(0,VICE_PAGE_SIZE,&(vice->dma_mem[i])))) {
+	    DPRINTK("failed at page# %i\n",i);
+    	    return -ENOMEM;
+	}
+    }
+    return 0;
+}
+static inline void vice_dma_mem_free(vice_dev *vice)
+{
+    int i;
+    for (i=0; i<64*2;i++){
+	if(vice->dma_kmem[i]) {
+	    pci_free_consistent(0,VICE_PAGE_ORDER,vice->dma_kmem[i],vice->dma_mem[i]);
+	    vice->dma_kmem[i]=0;
+	    vice->dma_mem[i]=0;
+	}
+    }
+}
+
+int vice_msp_init(vice_dev* vice);
+int vice_bsp_init(vice_dev* vice);
+int vice_dma_init(vice_dev* vice);
+
+void vice_msp_reset(vice_dev* vice);
+void vice_bsp_reset(vice_dev* vice);
+void vice_dma_reset(vice_dev* vice);
+
+void vice_msp_cleanup(vice_dev* vice);
+void vice_bsp_cleanup(vice_dev* vice);
+void vice_dma_cleanup(vice_dev* vice);
+
+void vice_dma_done(vice_dev* vice, int channel);
+void vice_dma_err(vice_dev* vice, int channel);
+void vice_handle_msp_int(vice_dev* vice);
+void vice_handle_msp_err(vice_dev* vice);
+void vice_handle_bsp_int(vice_dev* vice);
+void vice_handle_bsp_err(vice_dev* vice);
+void vice_handle_bus_err(vice_dev* vice);
+
+int vice_dma_run(vice_dev* vice,dma_run* run);
+int vice_msp_run(vice_dev* vice,msp_run* run);
+int vice_bsp_run(vice_dev* vice,bsp_run* run);
+#endif /* __KERNEL__ */
+
+#endif /* _VICE_H_ */
--- /dev/null	Sun Jul 17 16:46:18 1994
+++ drivers/char/o2vice/bsp.c	Tue Dec 10 09:54:48 2002
@@ -0,0 +1,161 @@
+/*
+ *
+ * Copyright (C) 2002 Ilya Volynets
+ *	Sponsored by Total Knowledge
+ *	http://www.total-knowledge.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *=======================================================================
+ * 09.16.2002	iluxa
+ *	- skeleton only (I don't have instruction set for BSP, so there
+ *	  is no way I can test it).
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>   /* printk() */
+#include <asm/page.h>
+#include <linux/vmalloc.h>   /* kmalloc() */
+#include <linux/fs.h>       /* everything... */
+#include <linux/errno.h>    /* error codes */
+#include <linux/types.h>    /* size_t */
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h>    /* O_ACCMODE */
+
+#include <asm/system.h>     /* cli(), *_flags */
+#include <asm/pci.h>
+#include <asm/uaccess.h>    /* put_user & friends */
+#include <asm/delay.h>
+
+/*
+ * The file operations for the bsp device
+ * (some are overlayed with primary vice)
+ */
+
+#include <linux/vice.h>
+
+
+/* wait queue to wait on while BSP runs */
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+void vice_bsp_reset(vice_dev* vice);
+
+/*
+ * Loads BSP PC with value form vice->bsp_pc, takes bsp out of reset
+ * state (just in case?) and kicks off execution.
+ */
+static inline void bsp_go(vice_dev* vice)
+{
+	vice_write_reg(BSP_HALT_RESET,BSP_OPERATIONAL); /* BSP_HALT=0 to start */
+}
+
+static inline void vice_bsp_stop()
+{
+    int i=0;
+    u64 ctl=vice_read_reg(BSP_HALT_RESET)|BSP_HALT;
+    vice_write_reg(BSP_HALT_RESET,ctl);
+    while(!vice_read_reg(BSP_HALT_RESET)&BSP_HALT_ACK) {
+	    if (++i>MAX_BSP_HALT_WAIT) {
+		    printk(KERN_WARNING "o2vice: timeout stopping bsp, bsp reset\n");
+		    vice_bsp_reset(0);/*FIXME: pass vice* arrond*/
+	    }
+	    udelay(16);
+    }
+}
+
+int vice_bsp_init(struct vice_dev* vice)
+{
+    spin_lock_init(&vice->dma_lock[1]);
+    return 0;
+}
+
+void vice_bsp_reset(vice_dev* vice)
+{
+    vice_write_reg(BSP_HALT_RESET,0);
+    vice_write_reg(BSP_FIFO_CTL_STAT, BSP_FIFO_CTL_RESET);
+    udelay(1);
+    vice_write_reg(BSP_HALT_RESET, BSP_OPERATIONAL|BSP_HALT);
+    vice_write_reg(BSP_FIFO_CTL_STAT,0);
+}
+void vice_bsp_cleanup(vice_dev* vice)
+{
+	vice_bsp_stop();
+}
+
+void vice_handle_bsp_int(vice_dev* vice)
+{
+    DPRINTK("Ah! We are done with BSP!\n");
+    if(vice->bsp_status!=VICE_RES_STATUS_INPROGRESS) {
+	DPRINTK("Ugh... BSP interrupt while BSP isn't started from driver!\n");
+	return;
+    }
+    vice->bsp_status=VICE_RES_STATUS_DONE;
+    vice->bsp_pc=-1; /* No exception, no EPC, and PC is probably
+			not one which executed Exception instruction */
+    vice->bsp_int_reason=vice_read_reg(BSP_CAUSE);
+    wake_up_interruptible(&wq);
+}
+void vice_handle_bsp_err(vice_dev* vice)
+{
+    DPRINTK("Ouch! BSP Exception!\n");
+    if(vice->bsp_status!=VICE_RES_STATUS_INPROGRESS) {
+	DPRINTK("Ugh... BSP exception while BSP isn't started from driver!\n");
+	return;
+    }
+    vice->bsp_status=VICE_RES_STATUS_ERR;
+    vice->bsp_pc=(u32)vice_read_reg(BSP_EPC);
+    vice->bsp_int_reason=vice_read_reg(BSP_CAUSE);
+    wake_up_interruptible(&wq);
+}
+
+int vice_bsp_run(vice_dev* vice, bsp_run* result)
+{
+    bsp_run r;
+    if(!access_ok(VERIFY_WRITE,result,sizeof(bsp_run)))
+	return -EFAULT;
+    DPRINTK("Checking for BSP status\n");
+    spin_lock_irq(vice->bsp_lock);
+    if(vice->bsp_status!=VICE_RES_STATUS_FREE) {
+	spin_unlock_irq(vice->bsp_lock);
+	return -EBUSY;
+    }
+    DPRINTK("BSP is free\n");
+    vice->bsp_status=VICE_RES_STATUS_INPROGRESS;
+    spin_unlock_irq(vice->bsp_lock);
+    DPRINTK("Kicking BSP off\n");
+    bsp_go(vice);
+    /*
+     * Sleep, untill BSP interrupts us...
+     *
+     * No spinlock is needed...
+     */
+    DPRINTK("Falling asleep\n");
+    while(vice->bsp_status==VICE_RES_STATUS_INPROGRESS) {
+        interruptible_sleep_on(&wq);
+	DPRINTK("Huh? Where am I?\n");
+	if(signal_pending(current))break;
+    }
+    DPRINTK("*yawn* obviously waking up....\n");
+    copy_from_user(&r,result,sizeof(r));
+    DPRINTK("r.reason=%x, r.pc=%x, r.status=%x\n",r.reason,r.pc,r.status);
+    r.status=vice->bsp_status;
+    vice->bsp_status=VICE_RES_STATUS_FREE;
+    r.pc=vice->bsp_pc;
+    r.reason=vice->bsp_int_reason;
+    DPRINTK("r.reason=%x, r.pc=%x, r.status=%x\n",r.reason,r.pc,r.status);
+    return copy_to_user(result,&r,sizeof(r));
+}
--- /dev/null	Sun Jul 17 16:46:18 1994
+++ drivers/char/o2vice/msp.c	Tue Dec 10 09:55:35 2002
@@ -0,0 +1,157 @@
+/*
+ *
+ * Copyright (C) 2002 Ilya Volynets
+ *	Sponsored by Total Knowledge
+ *	http://www.total-knowledge.com
+ *
+ * Development of this code was made possible by generous contribution
+ * from Total Knowledge (http://www.total-knowledge.com/)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * 09.16.2002	iluxa
+ *	- first rough cut. basic MSP operations supported
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>   /* printk() */
+#include <asm/page.h>
+#include <linux/vmalloc.h>   /* kmalloc() */
+#include <linux/fs.h>       /* everything... */
+#include <linux/errno.h>    /* error codes */
+#include <linux/types.h>    /* size_t */
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h>    /* O_ACCMODE */
+
+#include <asm/system.h>     /* cli(), *_flags */
+#include <asm/pci.h>
+#include <asm/uaccess.h>    /* put_user & friends */
+#include <asm/delay.h>
+
+/*
+ * The file operations for the msp device
+ * (some are overlayed with primary vice)
+ */
+
+#include <linux/vice.h>
+
+/* Statically allocate wait queue */
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+/*
+ * Loads MSP PC with value form msp->pc, takes msp out of reset
+ * state (just in case?) and kicks off execution.
+ */
+static inline void msp_go(vice_dev* vice)
+{
+    vice_write_reg(MSP_CTL_STAT,MSP_GO|MSP_OPERATIONAL);
+}
+
+static inline void vice_msp_stop(void)
+{
+    u64 ctl=vice_read_reg(MSP_CTL_STAT)&(~MSP_GO);
+    vice_write_reg(MSP_CTL_STAT,ctl);
+}
+
+int vice_msp_run(vice_dev *vice, msp_run* result)
+{
+    msp_run r;
+    if(!access_ok(VERIFY_WRITE,result,sizeof(msp_run)))
+	return -EFAULT;
+    DPRINTK("Checking for MSP status\n");
+    spin_lock_irq(vice->msp_lock);
+    if(vice->msp_status!=VICE_RES_STATUS_FREE) {
+	spin_unlock_irq(vice->msp_lock);
+	return -EBUSY;
+    }
+    DPRINTK("MSP is free\n");
+    vice->msp_status=VICE_RES_STATUS_INPROGRESS;
+    spin_unlock_irq(vice->msp_lock);
+    DPRINTK("Kicking MSP off\n");
+    msp_go(vice);
+    /*
+     * Sleep, untill MSP interrupts us...
+     *
+     * No spinlock is needed...
+     */
+    DPRINTK("Falling asleep\n");
+    while(vice->msp_status==VICE_RES_STATUS_INPROGRESS) {
+        interruptible_sleep_on(&wq);
+	DPRINTK("Huh? Where am I?\n");
+	if(signal_pending(current))break;
+    }
+    DPRINTK("*yawn* obviously waking up....\n");
+    copy_from_user(&r,result,sizeof(r));
+    DPRINTK("r.reason=%x, r.pc=%x, r.status=%x\n",r.reason,r.pc,r.status);
+    r.status=vice->msp_status;
+    vice->msp_status=VICE_RES_STATUS_FREE;
+    r.pc=vice->msp_pc;
+    r.reason=vice->msp_int_reason;
+    DPRINTK("r.reason=%x, r.pc=%x, r.status=%x\n",r.reason,r.pc,r.status);
+    return copy_to_user(result,&r,sizeof(r));
+}
+
+void vice_handle_msp_int(vice_dev* vice)
+{
+    DPRINTK("Ah! We are done with MSP!\n");
+    if(vice->msp_status!=VICE_RES_STATUS_INPROGRESS) {
+	DPRINTK("Ugh... MSP interrupt while MSP isn't started from driver!\n");
+	return;
+    }
+    vice->msp_status=VICE_RES_STATUS_DONE;
+    vice->msp_pc=-1; /* No exception, no EPC, and PC is probably
+			not one which executed Exception instruction */
+    vice->msp_int_reason=vice_read_reg(MSP_EXPT_FLAG);
+    wake_up_interruptible(&wq);
+}
+void vice_handle_msp_err(vice_dev* vice)
+{
+    DPRINTK("Ouch! MSP Exception!\n");
+    if(vice->msp_status!=VICE_RES_STATUS_INPROGRESS) {
+	DPRINTK("Ugh... MSP exception while MSP isn't started from driver!\n");
+	return;
+    }
+    vice->msp_status=VICE_RES_STATUS_ERR;
+    vice->msp_pc=(u32)vice_read_reg(MSP_EPC);
+    vice->msp_int_reason=vice_read_reg(MSP_EXPT_FLAG);
+    /* clear any exception bits */
+    vice_write_reg(MSP_EXPT_FLAG,0x00);
+    wake_up_interruptible(&wq);
+}
+
+int vice_msp_init(struct vice_dev* vice)
+{
+    spin_lock_init(&vice->dma_lock[0]);
+    return 0;
+}
+
+void vice_msp_reset(vice_dev *vice)
+{
+    /* start reset */
+    vice_write_reg(MSP_CTL_STAT,0);
+    /* wait for reset to complete */
+    udelay(1);
+    /* take out of reset, and prepare to go */
+    vice_write_reg(MSP_CTL_STAT,MSP_OPERATIONAL);
+    /* let MSP access all VICE internal RAM */
+    vice_write_reg(MSP_D_RAM,0x7);
+}
+
+void vice_msp_cleanup(vice_dev* vice)
+{
+    vice_msp_stop();
+}
--- /dev/null	Sun Jul 17 16:46:18 1994
+++ drivers/char/o2vice/Kconfig	Sat Nov  2 14:10:16 2002
@@ -0,0 +1,32 @@
+#
+# O2 VICE Engine confiuration
+#
+
+config O2_VICE
+    tristate "O2 VICE Engine Support"
+    depends on SGI_IP32
+    ---help---
+      This option enables O2 VICE Engine support.
+      VICE stands for Video Image Compression Engine. This is very powerfull
+      piece of silicon, that can greatly speed up lots of graphics, vide, or
+      sound related tasks. To be able to use it, you will also need special
+      library, that can be found at <insert URL here>
+
+config O2_VICE_DBGG
+    bool "VICE Debugger Support. READ HELP!"
+    depends on O2_VICE
+    ---help---
+      This option enables features of VICE driver needed to debug VICE library.
+      This is probably serious security risk. You don't need it. If you think
+      you do, you are wrong. Say NO.
+
+config O2_VICE_DBG
+    bool "You seem to insist... did you read help? Yes? No? READ HELP!"
+    depends on O2_VICE_DBGG
+    ---help---
+      You are still here? Didn't I just tell you that it is not needed?
+      Or do you want to say you *legally* obtained information needed for
+      programming VICE? That you got all the tools needed? As a matter of
+      fact, these tools don't even exist yet!
+
+      Sigh... You've been warned...
--- /dev/null	Sun Jul 17 16:46:18 1994
+++ drivers/char/o2vice/Makefile	Thu Sep 12 00:12:16 2002
@@ -0,0 +1,21 @@
+#
+# drivers/char/o2vice/Makefile
+#
+# Makefile for the O2 VICE Engine driver.
+#
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+#O_TARGET := vice.o
+
+obj-y		:=
+obj-m		:=
+obj-n		:=
+obj-		:=
+
+obj-$(CONFIG_O2_VICE)	+= main.o msp.o bsp.o dma.o
+#obj-$(CONFIG_O2_VICE_DBG) += vicedebug.o
+
+include $(TOPDIR)/Rules.make
--- /dev/null	Sun Jul 17 16:46:18 1994
+++ drivers/char/o2vice/main.c	Tue Dec 10 09:55:59 2002
@@ -0,0 +1,438 @@
+/*
+ * main.c -- SGI O2 VICE driver
+ *
+ * The code skeleton came from the book "Linux Device
+ * Drivers" by Alessandro Rubini and Jonathan Corbet, published
+ * by O'Reilly & Associates.   No warranty is attached;
+ * we cannot take responsibility for errors or fitness for use.
+ *
+ * Copyright (C) 2002 Ilya Volynets.
+ *	Sponsored by Total Knowledge
+ *	http://www.total-knowledge.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *======================================================================
+ * 09.16.2002	iluxa
+ *	- first rough cut is ready.
+ */
+
+/*
+ * When debugging support is turned off, there will be no access to most of
+ * VICE I/O space. No PIO access to ram and buffers for sure, as acceessing
+ * some of "unimplemented" regions seems to halt system completely. (Is CPU
+ * just stalling, waiting for data to be returned, instead of getting error?)
+ * Safe registers are first 4K (control registers?) and next 4K with DMA
+ * describtors.
+ * Well, I could give access to correct pages through "nopage" method...
+ * Then accessing "reserved" regions would give SIG_BUS...
+ * Data ram would be problem: there are 3 2K regions, which either makes
+ * only 2 banks accessible to userspace, or none at all (giving non-root user
+ * an option to randomly hang system is not an option :)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>		/* module_(init|exit) */
+
+#include <linux/kernel.h>	/* printk() */
+#include <asm/page.h>
+#include <linux/vmalloc.h>	/* kmalloc() */
+#include <linux/fs.h>		/* everything... */
+#include <linux/errno.h>	/* error codes */
+#include <linux/types.h>	/* size_t */
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h>	/* O_ACCMODE */
+
+#include <asm/system.h>		/* cli(), *_flags */
+
+#include <linux/mm.h>
+
+#include <linux/vice.h>		/* local definitions */
+
+#include <asm/ip32/ip32_ints.h>
+
+int vice_major = VICE_MAJOR;
+
+MODULE_PARM(vice_major, "i");
+MODULE_AUTHOR("Ilya Volynets");
+
+const char *vice_str="vice";
+
+/*
+ * Different minors behave differently, so let's use multiple fops
+ */
+
+
+void *vice_device;	/* holds pointer to vice state (allocated in module_init) */
+
+/*
+ * vice_reset -- restes VICE engine
+ */
+int vice_reset(vice_dev * dev)
+{
+    vice_bsp_reset(dev);
+    vice_msp_reset(dev);
+    vice_dma_reset(dev);
+    return 0;
+}
+
+void vice_handle_buserr(vice_dev* vice)
+{
+    printk(KERN_WARNING "vice: received \"Erroneous data\" interrupt.\n");
+    printk(KERN_WARNING "\tUnfortunately I (Ilya Volynets) Have no idea what is it, so I'm simply ignoring it.\n");
+}
+
+static void vice_interrupt(int irq, void *dev_id, struct pt_regs *pregs)
+{
+    struct vice_dev *vice = (struct vice_dev *) dev_id;
+    u64 status;
+    DPRINTK("irq!\n");
+    status=vice_read_reg(VICE_INT);
+
+    if (!vice /*paranoid */ ) {
+	DPRINTK ("Paranoja ouch!\n");
+	return;
+    }
+
+    DPRINTK("Interrupt, status %016lx...\n", status);
+    if (status & VICE_INT_DMA_CH1_DONE)
+	vice_dma_done(vice,0);
+    if (status & VICE_INT_DMA_CH1_ERR)
+	vice_dma_err(vice,0);
+    if (status & VICE_INT_DMA_CH2_DONE)
+	vice_dma_done(vice,1);
+    if (status & VICE_INT_DMA_CH2_ERR)
+	vice_dma_err(vice,1);
+    if (status & VICE_INT_MSP_SW)
+	vice_handle_msp_int(vice);
+    if (status & VICE_INT_MSP_ERR)
+	vice_handle_msp_err(vice);
+    if (status & VICE_INT_BSP_SW)
+	vice_handle_bsp_int(vice);
+    if (status & VICE_INT_BSP_ERR)
+	vice_handle_bsp_err(vice);
+    if (status & VICE_INT_BUSERR)
+	vice_handle_buserr(vice);
+
+    vice_write_reg(VICE_INT_RESET,0x1FF);	/* clear handled interrupts */
+}
+
+/*
+ * Open and close
+ */
+
+/* In vice_open, the fop_array is used according to TYPE(dev) */
+int vice_open(struct inode *inode, struct file *filp)
+{
+    vice_dev *vice=vice_device;		/* device information */
+    int res;
+
+    MOD_INC_USE_COUNT;		/* Before we maybe sleep */
+
+    if(vice->is_open)
+	return -EBUSY;
+
+    if (!filp->private_data) {
+	filp->private_data = vice_device;
+    }
+
+    vice_reset(vice);
+
+    if ((res=request_irq(CRIME_VICE_IRQ, vice_interrupt, SA_SHIRQ, vice_str, vice))) {
+	printk(KERN_ERR "vice: Can't get irq %x: res=%i\n", (unsigned int)CRIME_VICE_INT, res);
+	return res;
+    }
+
+    /*Actual device init goes in here */
+
+    {
+	int ret;
+	if((ret=vice_dma_mem_init(vice))!=0) {
+	    DPRINTK("Failure allocating VICE I/O buffers...\n");
+	    vice_dma_mem_free(vice);
+	    DPRINTK("Freed already-allocated memory...\n");
+	    return ret;
+	}
+	/* enable interrupts in VICE */
+        vice_write_reg(VICE_INT_RESET,0x1FF); /* clear pending interrupts */
+	vice_write_reg(VICE_INT_EN,0x1FF);
+    }
+    vice->is_open=1;
+    return 0;			/* success */
+}
+
+int vice_release(struct inode *inode, struct file *filp)
+{
+    vice_dev *vice=(vice_dev*)filp->private_data;
+
+    DPRINTK("closing down\n");
+    if(!vice->is_open) {
+	DPRINTK("Uuoouuuuch! Closing unopen file!!!!\n");
+	return -EINVAL; /*? Should I return something else? -ENOTOPEN? */
+    }
+    /* disable interrupts in VICE */
+    vice_write_reg(VICE_INT_EN,0x000);
+    free_irq(CRIME_VICE_IRQ, vice);
+    vice_dma_mem_free(vice);
+    vice_reset(vice);
+    vice->is_open=0;
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+/*
+ * Data management: read and write
+ */
+
+ssize_t vice_read(struct file * filp, char *buf, size_t count, loff_t * f_pos)
+{
+    printk(KERN_WARNING
+	   "Processing bit streams through reading/writing is not supported yet\n");
+    return -ENOSYS;
+}
+
+ssize_t vice_write(struct file * filp, const char *buf, size_t count,
+	   loff_t * f_pos)
+{
+    printk(KERN_WARNING
+	   "Processing bit streams through reading/writing is not supported (yet)\n");
+    return -ENOSYS;
+}
+
+/*
+ * The ioctl() implementation
+ */
+
+int vice_ioctl(struct inode *inode, struct file *filp,
+	   unsigned int cmd, unsigned long arg)
+{
+    vice_dev *vice=(vice_dev*)filp->private_data;
+
+    switch(cmd) {
+    case VICE_IOCTL_MAP_DMA:
+	return vice_dma_map_set(vice,arg);
+    case VICE_IOCTL_MSP_RUN:
+	return vice_msp_run(vice,(msp_run*)arg);
+    case VICE_IOCTL_BSP_RUN:
+	return vice_bsp_run(vice,(bsp_run*)arg);
+    case VICE_IOCTL_DO_DMA:
+	return vice_dma_run(vice,(dma_run*)arg);
+    default:
+	return -ENOTTY;
+    }
+    return 0;
+}
+
+/*
+ * Common VMA ops.
+ */
+
+static void vice_vma_open(struct vm_area_struct *vma)
+{ MOD_INC_USE_COUNT; }
+
+static void vice_vma_close(struct vm_area_struct *vma)
+{ MOD_DEC_USE_COUNT; }
+/*
+ * All it does is find 4K page in one of 64K pages from vice->dev_mem
+ * There is no need to worry about I/O addresses here, since they are remap_page_ranged
+ * on initial mmap....
+ */
+struct page* vice_vma_nopage(struct vm_area_struct *vma,unsigned long address, int write)
+{
+    vice_dev *vice=(vice_dev*)vma->vm_private_data;
+    unsigned long fkpn=((address-vma->vm_start)>>PAGE_SHIFT)+
+	    (vma->vm_pgoff-(VICE_MIN_OFFSET>>PAGE_SHIFT));
+    unsigned long v_pn=fkpn>>VICE_PAGE_ORDER;
+    unsigned long kaddr;
+    struct page *pgptr;
+    if(v_pn>=sizeof(vice->dma_mem)/sizeof(vice->dma_mem[0]))
+	return NOPAGE_SIGBUS;
+    kaddr=(unsigned long)KSEG0ADDR(vice->dma_kmem[v_pn])+((fkpn-(v_pn<<VICE_PAGE_ORDER))<<PAGE_SHIFT);
+    pgptr=virt_to_page(vice->dma_kmem[v_pn]);
+    get_page(pgptr);
+    return virt_to_page(kaddr);
+}
+
+static struct vm_operations_struct vice_vm_ops = {
+    open:  vice_vma_open,
+    close: vice_vma_close,
+    nopage: vice_vma_nopage,
+};
+
+/*
+ * mmap I/O registers of VICE. Called when region is in 0-VICE_IO_MAX range.
+ */
+static inline int vice_io_mmap( struct vm_area_struct *vma)
+{
+    unsigned long offset=vma->vm_pgoff<<PAGE_SHIFT;
+    if(offset+vma->vm_end-vma->vm_start>VICE_IO_MAX_OFFSET+1) {
+	DPRINTK("invalid offset: %lu,length=%lx\n",offset,vma->vm_end-vma->vm_start);
+	return -EINVAL;
+    }
+    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+    vma->vm_flags |= VM_IO|VM_RESERVED;
+    flush_cache_all();
+    return remap_page_range(vma,vma->vm_start,VICE_BASE+offset,vma->vm_end-vma->vm_start,vma->vm_page_prot);
+}
+/*
+ * mmap I/O buffers. Called when region is above VICE_IO_MAX.
+ */
+
+static inline int vice_buffer_mmap( struct file* filep, struct vm_area_struct *vma)
+{
+    vice_dev *vice=(vice_dev*)filep->private_data;
+    unsigned long offset=vma->vm_pgoff<<PAGE_SHIFT;
+
+    /* must be VICE_PAGE aligned (64K) and size must be ... by 64K */
+    if (offset&0xFFFF||(vma->vm_end-vma->vm_start)&0xFFFF)
+	return -ENXIO; /* alignment error? */
+
+    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+    vma->vm_flags |= VM_IO|VM_RESERVED;
+
+    vma->vm_private_data=vice;
+    vma->vm_file = filep;
+    return 0;
+}
+
+static int vice_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+    unsigned long offset=vma->vm_pgoff<<PAGE_SHIFT;
+    vma->vm_ops = &vice_vm_ops;
+    if(offset<=VICE_IO_MAX_OFFSET)
+	return vice_io_mmap(vma);
+    else if(offset>=VICE_MIN_OFFSET&&offset+vma->vm_end-vma->vm_start<=VICE_MAX_OFFSET)
+	return vice_buffer_mmap(filp,vma);
+    else
+	return -EINVAL;
+    vice_vma_open(vma);
+}
+
+struct file_operations vice_fops = {
+    read:vice_read,
+    write:vice_write,
+    ioctl:vice_ioctl,
+    open:vice_open,
+    release:vice_release,
+    mmap:vice_mmap,
+};
+
+/*
+ * Finally, the module stuff
+ */
+
+#ifdef CONFIG_DEVFS_FS
+devfs_handle_t vice_devfs_dir;
+static char devname[4];
+#endif
+
+/*
+ * The cleanup function is used to handle initialization failures as well.
+ * Thefore, it must be careful to work correctly even if some of the items
+ * have not been initialized
+ */
+void vice_cleanup_module(void)
+{
+#ifndef CONFIG_DEVFS_FS
+    /* cleanup_module is never called if registering failed */
+    unregister_chrdev(vice_major, "vice");
+#endif
+
+    /* Cleanup MSP/BSP/DMA */
+    /* This really should be done in close.. */
+    vice_msp_cleanup(vice_device);
+    vice_bsp_cleanup(vice_device);
+    vice_dma_cleanup(vice_device);
+
+    /* Clean up DMA and other HW */
+
+    if (vice_device) {
+	kfree(vice_device);
+    }
+#ifdef CONFIG_DEVFS_FS
+    /* once again, only for devfs */
+    devfs_unregister(vice_devfs_dir);
+#endif
+}
+
+
+int vice_init_module(void)
+{
+    int result;
+    vice_dev *vice;
+
+    SET_MODULE_OWNER(&vice_fops);
+#ifdef CONFIG_DEVFS_FS
+    /* If we have devfs, create /dev/vice to put files in there */
+    vice_devfs_dir = devfs_mk_dir(NULL, "vice", NULL);
+    if (!vice_devfs_dir)
+	return -EBUSY;		/* problem */
+
+#else				/* no devfs, do it the "classic" way  */
+
+    /*
+     * Register your major, and accept a dynamic number. This is the
+     * first thing to do, in order to avoid releasing other module's
+     * fops in vice_cleanup_module()
+     */
+    result = register_chrdev(vice_major, "vice", &vice_fops);
+    if (result < 0) {
+	printk(KERN_WARNING "vice: can't get major %d\n", vice_major);
+	return result;
+    }
+    if (vice_major == 0)
+	vice_major = result;	/* dynamic */
+
+#endif				/* CONFIG_DEVFS_FS */
+    /* 
+     * allocate the devices -- we could have them static, but... I dunno...
+     */
+    vice = kmalloc(sizeof(vice_dev), GFP_KERNEL);
+    if (!vice) {
+	result = -ENOMEM;
+	goto fail;
+    }
+    vice_device = vice;
+    memset(vice, 0, sizeof(vice_dev));
+#ifdef CONFIG_DEVFS_FS
+    devfs_register(vice_devfs_dir, "vice",
+		   DEVFS_FL_AUTO_DEVNUM,
+		   0, 0, S_IFCHR | S_IRUGO | S_IWUGO, &vice_fops, vice);
+#endif
+    if ((result = vice_dma_init(vice)))
+	goto fail;
+    /* Initialize MSP & BSP */
+    if ((result = vice_msp_init(vice)))
+	goto fail;
+    if ((result = vice_bsp_init(vice)))
+	goto fail;
+
+#ifndef VICE_DEBUG
+    EXPORT_NO_SYMBOLS;		/* otherwise, leave global symbols visible */
+#endif
+
+    vice_write_reg(VICE_ID,0xfffff);
+#define ID_BITS 0xF
+    printk("SGI O2 VICE rev. %ld\n", vice_read_reg(VICE_ID)&ID_BITS);
+    return 0;			/* succeed */
+
+  fail:
+    vice_cleanup_module();
+    return result;
+}
+
+module_init(vice_init_module);
+module_exit(vice_cleanup_module);
--- /dev/null	Sun Jul 17 16:46:18 1994
+++ drivers/char/o2vice/dma.c	Sat Nov  2 16:36:05 2002
@@ -0,0 +1,183 @@
+/*
+ *
+ * Copyright (C) 2002 Ilya Volynets
+ *	Sponsored by Total Knowledge
+ *	http://www.total-knowledge.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *======================================================================
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>   /* printk() */
+#include <asm/page.h>
+#include <linux/vmalloc.h>  /* kmalloc() */
+#include <linux/fs.h>       /* everything... */
+#include <linux/errno.h>    /* error codes */
+#include <linux/types.h>    /* size_t */
+#include <linux/proc_fs.h>
+#include <linux/fcntl.h>    /* O_ACCMODE */
+#include <linux/sched.h>
+
+#include <asm/system.h>     /* cli(), *_flags */
+#include <asm/pci.h>
+#include <asm/uaccess.h>    /* put_user & friends */
+#include <asm/delay.h>
+
+#include <asm/errno.h>
+#include <asm/addrspace.h>
+
+/*
+ * VICE DMA support
+ */
+
+#include <linux/vice.h>
+
+/* wait queue to sleep on, while waiting for DMA */
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+
+
+/*
+ * Maps one of 4M sets into VICE TLB.
+ * Currently set# can be either 0 or 1
+ */
+int vice_dma_map_set(vice_dev *vice,unsigned long set)
+{
+    unsigned long *page_set;
+    int i;
+    /* either map in 0th or 1st set (for now....) */
+    if(set>=2)
+	return -EINVAL;
+    page_set=&(vice->dma_mem[VICE_TLB_ENTRIES*set]);
+    for(i=0; i<VICE_TLB_ENTRIES; i++) {
+	vice_write_reg(VICE_TLB_OFFSET+(i<<3), page_set[i]|VICE_TLB_VALID|VICE_TLB_WRITABLE);
+    }
+    for(i=0; i<VICE_TLB_ENTRIES; i++) {
+	printk("%016lx ",vice_read_reg(VICE_TLB_OFFSET+(i<<3)));
+    }
+    printk("\n");
+    return 0;
+}
+
+/*
+ * Unmaps all pages from VICE TLB
+ */
+int vice_dma_clear_tlb(vice_dev *vice)
+{
+    int i;
+    for(i=0; i<VICE_TLB_ENTRIES; i++) {
+	vice_write_32(VICE_TLB_OFFSET+(i<<2), 0);
+    }
+    return 0;
+}
+
+int vice_dma_init(vice_dev* vice)
+{
+    int ret=0;
+    spin_lock_init(&vice->dma_lock[0]);
+    spin_lock_init(&vice->dma_lock[1]);
+    return ret;
+}
+
+int vice_dma_run(vice_dev* vice,dma_run* run)
+{
+    dma_run r;
+    if(copy_from_user(&r,run,sizeof(r)))
+	return -EINVAL;
+    if(r.channel>=2)
+	return -EINVAL;
+
+    /*
+     * Only reason I need this spinlock is if two threads are trying to
+     * _start_ DMA at the same time. All other accesses to dma_status need not
+     * be interlocked.
+     */
+    DPRINTK("Checking for channel status\n");
+    spin_lock_irq(vice->dma_lock[r.channel]);
+    if(vice->dma_status[r.channel]!=VICE_RES_STATUS_FREE) {
+	spin_unlock_irq(vice->dma_lock[r.channel]);
+	return -EBUSY;
+    }
+    DPRINTK("Channel OK\n");
+    vice->dma_status[r.channel]=VICE_RES_STATUS_INPROGRESS;
+    spin_unlock_irq(vice->dma_lock[r.channel]);
+    DPRINTK("Kicking DMA off\n");
+    if(r.channel==0)
+        vice_write_reg(DMA_CH1_CTL,r.desc|VICE_DMA_CTL_GO|VICE_DMA_CTL_IE);
+    else
+	vice_write_reg(DMA_CH2_CTL,r.desc|VICE_DMA_CTL_GO|VICE_DMA_CTL_IE);
+    /*
+     * Sleep, untill this channel sends DMA_DONE or DMA_ERR interrupt...
+     *
+     * No spinlock is needed...
+     */
+    DPRINTK("Falling asleep\n");
+    while(vice->dma_status[r.channel]==VICE_RES_STATUS_INPROGRESS) {
+        interruptible_sleep_on(&wq);
+	DPRINTK("Huh? Where am I?\n");
+	if(signal_pending(current))break;
+    }
+    DPRINTK("*yawn* obviously waking up....\n");
+    r.status=vice->dma_status[r.channel];
+    vice->dma_status[r.channel]=VICE_RES_STATUS_FREE;
+    __copy_to_user(&r,run,sizeof(r));
+    DPRINTK("Done\n");
+    return 0;
+}
+
+void vice_dma_done(vice_dev *vice, int channel)
+{
+    DPRINTK("DMA done\n");
+
+    if(vice->dma_status[channel]!=VICE_RES_STATUS_INPROGRESS) {
+	DPRINTK("Ugh... DMA interrupt on channel %d, while DMA on that channel isn't initiated from CPU!\n",channel);
+	return;
+    }
+    vice->dma_status[channel]=VICE_RES_STATUS_DONE;
+    wake_up_interruptible(&wq);
+}
+
+void vice_dma_err(vice_dev *vice, int channel)
+{
+    DPRINTK("DMA error\n");
+    spin_lock_irq(vice->dma_lock[channel]);
+    vice->dma_status[channel]=VICE_RES_STATUS_ERR;
+    spin_unlock_irq(vice->dma_lock[channel]);
+    wake_up_interruptible(&wq);
+}
+
+/*
+ * Need to stop all DMA transfers
+ */
+
+void vice_dma_cleanup(vice_dev* vice)
+{
+}
+
+void vice_dma_reset(vice_dev* vice)
+{
+    /*
+     * Is DMA engine resettable?
+     * ... Yes, which register?
+     */
+    vice_write_reg(DMA_CH1_CTL,VICE_DMA_CTL_RESET);
+    vice_write_reg(DMA_CH2_CTL,VICE_DMA_CTL_RESET);
+    udelay(16); /* sleep for at least 16 VICE clocks */
+    vice_write_reg(DMA_CH1_CTL,VICE_DMA_CTL_IE|VICE_DMA_CTL_DESC1);
+    vice_write_reg(DMA_CH2_CTL,VICE_DMA_CTL_IE|VICE_DMA_CTL_DESC1);
+    vice_dma_clear_tlb(vice);
+}

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

             reply	other threads:[~2002-12-10 19:11 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-12-10 19:11 ilya [this message]
2002-12-11 13:38 ` O2 VICE support Christoph Hellwig
2002-12-11 22:16   ` ilya
2002-12-11 22:45     ` Christoph Hellwig
2002-12-11 22:46     ` Juan Quintela
2002-12-22  9:20 ` Geert Uytterhoeven

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20021210191120.GE609@gateway.total-knowledge.com \
    --to=ilya@theilya.com \
    --cc=linux-mips@linux-mips.org \
    --cc=ralf@linux-mips.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.