Attached is patch set to add support to kernel for O2 video compression engine (VICE). It should apply cleanly to latest CVS. Ilya.
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:
pgp00243.pgp
Description: PGP signature