?? dsp.c
字號:
/* * MPEG Audio DSP Player Linux Module v0.1 * copyrights (c) 1996 by Michael Hipp * * Read the README file before using the software!! *//* * gcc -O2 -Wall -m486 -fomit-frame-pointer -DMODULE -D__KERNEL__ -c dsp.c */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/malloc.h>#include <linux/string.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/errno.h>#include "dsp_ld.h"#define BUFFER_SIZE 16384#define DSP_MAJOR 62struct cd { unsigned char bufs[2][BUFFER_SIZE]; int rbuf; int wbuf; int rpos; int wpos; int state; int wsize,rsize; struct wait_queue *waitq; int base_addr; int dma; int irq; int interrupt;};static int dsp_open_dev(struct inode * inode, struct file * file);static void dsp_release_dev(struct inode * inode, struct file * file);static int dsp_read_dev(struct inode * inode, struct file * file,char *,int);static int dsp_write_dev(struct inode * inode, struct file * file,const char *,int);static int dsp_reset(struct cd *p);static int dsp_write(struct cd *d,unsigned char *buf,int count,int source);static int dsp_probe(struct cd *p);static void dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs);static void dsp_init(struct cd *p, unsigned char *,int m);#define PSS_DATA 0x00#define PSS_STATUS 0x02#define PSS_CONTROL 0x02#define PSS_ID_VERS 0x04#define PSS_CONFIG 0x10#define WSS_CONFIG 0x12#define SB_CONFIG 0x14#define CD_CONFIG 0x16#define MIDI_CONFIG 0x18#define DSP_OPEN 0x1#define DSP_WRITE_READY 0x2#define DSP_RELEASE_WAIT 0x4static struct file_operations dsp_fops = { NULL, NULL, /* read */ dsp_write_dev, /* write */ NULL, /* readdir */ NULL, /* select */ NULL, NULL, /* lp_mmap */ dsp_open_dev, dsp_release_dev};int debug = 0;#define NUM_DEV 1static struct cd devs[NUM_DEV];static int minor2dspnum[3] = { -1 , -1 , -1 };static int dsp_open_dev(struct inode * inode, struct file * file){ unsigned int minor = MINOR(inode->i_rdev); int dspnum; int i; if(debug) printk(KERN_DEBUG "dsp_open %d\n",minor); if(minor < 0 || minor > 2) { return -ENODEV; } for(i=0;i<3;i++) /* currently, only one DSP supported */ if(minor2dspnum[i] >= 0) return -EAGAIN; minor2dspnum[minor] = 0; dspnum = minor2dspnum[minor]; if(devs[dspnum].state) return -EBUSY; MOD_INC_USE_COUNT; devs[dspnum].state = DSP_OPEN; devs[dspnum].rsize = devs[dspnum].wsize = BUFFER_SIZE; devs[dspnum].rpos = 0; devs[dspnum].wpos = 0; devs[dspnum].rbuf = 0; devs[dspnum].wbuf = 0; dsp_init(&devs[dspnum],dspcode,sizeof(dspcode)); return 0;}static void dsp_release_dev(struct inode * inode, struct file * file){ unsigned int minor = MINOR(inode->i_rdev); int dspnum; if(debug) printk(KERN_DEBUG "dsp_release %d\n",minor); if(minor < 0 || minor > 2) { return; } dspnum = minor2dspnum[minor]; if(dspnum < 0 || !devs[dspnum].state) return; if(devs[dspnum].wpos > 0 && (devs[dspnum].wpos < devs[dspnum].wsize) ) /* buffer not empty */ { char buf[1] = { 0 }; devs[dspnum].wsize = devs[dspnum].wpos + 1; dsp_write(&devs[dspnum],buf,1,1); } devs[dspnum].state = DSP_RELEASE_WAIT; while(devs[dspnum].wbuf != devs[dspnum].rbuf) interruptible_sleep_on(&(devs[dspnum].waitq)); minor2dspnum[minor] = -1; devs[dspnum].state = 0;#if 0 dsp_reset(devs[dspnum].dev); wake_up_interruptible(&devs[dspnum].waitq);#endif MOD_DEC_USE_COUNT;}static int dsp_write_dev(struct inode * inode, struct file * file,const char *buf , int count){ unsigned int minor = MINOR(inode->i_rdev); struct cd *d; int r,dspnum; if(minor < 0 || minor > 2) return -ENODEV; dspnum = minor2dspnum[minor]; if(dspnum < 0 || !devs[dspnum].state) return -ENXIO; if ((r = verify_area(VERIFY_READ, (void *) buf, count))) return r; d = &devs[dspnum]; return dsp_write(d,(unsigned char *) buf,count,0);}static int dsp_write(struct cd *d,unsigned char *buf,int count,int source){ int cnt1 = count; int pos = 0; while(cnt1) { if(d->wpos < d->wsize) { int len = d->wsize - d->wpos; if(len > cnt1) len = cnt1; if(debug) printk("got %d bytes\n",len); if(source) memcpy(d->bufs[d->wbuf]+d->wpos,buf+pos,len); else memcpy_fromfs(d->bufs[d->wbuf]+d->wpos,buf+pos,len); pos += len; d->wpos += len; cnt1 -= len; } if(d->wpos >= d->wsize) { if(d->wbuf == d->rbuf) { long flags; d->wbuf++; d->wbuf &= 0x1; d->wpos = 0; d->rpos = 0; d->rsize = d->wsize; d->wsize = BUFFER_SIZE; save_flags(flags); cli(); if( (inw(d->base_addr+PSS_STATUS) & 0x8000) ) { unsigned short w; w = d->bufs[d->rbuf][d->rpos]<<8; w |= d->bufs[d->rbuf][d->rpos+1]; if(debug) printk("initial write %02x\n",w);#if 0 outw(0x8000,d->base_addr+PSS_CONTROL);#endif outw(w,d->base_addr+PSS_DATA); d->rpos+=2; } restore_flags(flags); } else if(cnt1 > 0){ interruptible_sleep_on(&(d->waitq)); if(debug) printk("waked up %d %d\n",d->state,d->wpos); if(!d->state || d->wpos >= d->wsize) return 0; } } } return count;}static int dsp_read_dev(struct inode * inode, struct file * file, char *buf , int count){ unsigned int minor = MINOR(inode->i_rdev); int dspnum; if(minor < 0 || minor > 2) { return -ENODEV; } dspnum = minor2dspnum[minor]; if(dspnum < 0 || !devs[dspnum].state) return -ENXIO; return 0;}int dsp_probe(struct cd *p){ static int irqtab[] = { -1,-1,-1,0x1,-1,0x2,-1,0x3,-1,0x4,0x5,0x6,0x7 ,-1,-1,-1 }; static int dmatab[] = { 0x1,0x2,-1,0x3,-1,0x5,0x6,0x7 }; unsigned short w; int dspnum = 0; p = &devs[dspnum]; outw(0,p->base_addr + PSS_CONFIG); outw(0,p->base_addr + WSS_CONFIG); outw(0,p->base_addr + SB_CONFIG); outw(0,p->base_addr + CD_CONFIG); outw(0,p->base_addr + MIDI_CONFIG); /* Grab the region so that no one else tries to probe our ioports. */ if(p->dma <= 7 && dmatab[p->dma] < 0) { printk("illegal DMA %d\n",p->dma); return -EAGAIN; } if(p->irq < 0 || p->irq > 15 || irqtab[p->irq] < 0) { printk("illegal IRQ %d\n",p->irq); return -EAGAIN; } if(check_region(p->base_addr, 0x20 )) { printk("dsp: region %#x-%#x in use.\n",p->base_addr,p->base_addr+0x20);#if 0 return -EAGAIN;#endif } request_region(p->base_addr, 0x20 ,"dsp"); if (request_irq(p->irq, &dsp_interrupt, 0, "dsp", NULL)) { printk("Can't get IRQ %d\n",p->irq); release_region(p->base_addr,0x20); return -EAGAIN; } if(p->dma <= 7) { if(request_dma(p->dma,"dsp")) { printk("Can'T get DMA %d\n",p->dma); free_irq(p->irq,NULL); release_region(p->base_addr,0x20); return -EAGAIN; } w = (irqtab[p->irq]<<3) | dmatab[p->dma]; } else { w = (irqtab[p->irq]<<3); } irq2dev_map[p->irq] = p; outw(w,p->base_addr+PSS_CONFIG); dsp_init(p,dspcode,sizeof(dspcode)); return 0;}static void dsp_interrupt(int irq, void *dev_id, struct pt_regs * regs){ struct cd *p = (struct cd *)(irq2dev_map[irq]); int stat; int fail = 32; int mask = 0xf000; if (p == NULL) { printk(KERN_WARNING "%s: irq %d for unknown device.\n", "dsp" , irq); return; } if(set_bit(0,&p->interrupt)) return; stat=inw(p->base_addr+PSS_STATUS); if(stat & 0x3000) { outw(0x0,p->base_addr+0x4); } while( (stat & mask) && fail ) { fail--; if(stat & 0x4000) { int k = inw(p->base_addr+PSS_DATA); printk("dsp->%04x ",k); } if(stat & 0x8000) { if(p->state && p->wbuf != p->rbuf) { unsigned short w; w = p->bufs[p->rbuf][p->rpos]<<8; w |= p->bufs[p->rbuf][p->rpos+1]; outw(w,p->base_addr+PSS_DATA); p->rpos+=2; if(p->rpos >= p->rsize) { p->rbuf++; p->rbuf &= 0x1; p->rpos = 0; if(p->wpos >= p->wsize) { p->rsize = p->wsize; p->wbuf++; p->wbuf &= 0x1; p->wpos = 0; p->wsize = BUFFER_SIZE; } wake_up_interruptible(&(p->waitq)); } } else {#if 0 mask = 0x7000;#endif } } stat=inw(p->base_addr+PSS_STATUS); } p->interrupt = 0; return;}static int dsp_reset(struct cd *p){ int i; outw (0x2000,p->base_addr + PSS_CONTROL); for (i = 0; i < 32768 ; i++) inw (p->base_addr + PSS_CONTROL); outw (0x0000,p->base_addr + PSS_CONTROL); return 1;}static void dsp_init(struct cd *p,unsigned char *block,int len ){ int i,j; unsigned char *pnt1 = block; dsp_reset(p); outw(*block++,p->base_addr+PSS_DATA); dsp_reset(p); for(i=0;;i++) { for(j=0;j<100000;j++) if(inw(p->base_addr+PSS_STATUS) & 0x800) break; if(j==100000) { printk("dsp TIMEOUT.\n"); break; } if(i == len-1) break; outw(*block++,p->base_addr+PSS_DATA); } printk("downloaded code: %d\n",block-pnt1);#if 0 outw(0x4000,p->base_addr+PSS_CONTROL);#endif outw(0,p->base_addr+PSS_DATA);}#ifdef MODULEstatic int io = 0x220;static int irq = 10;static int dma = 255;int init_module(void){ int result,i; /* Copy the parameters from insmod into the device structure. */ devs[0].base_addr = io; devs[0].irq = irq; devs[0].dma = dma; for(i=0;i<NUM_DEV;i++) { devs[i].state = 0; devs[i].waitq = NULL; } if (register_chrdev(DSP_MAJOR, "dsp", &dsp_fops)) { printk(KERN_WARNING "dsp: Could not register control devices\n"); return -EIO; } result = dsp_probe(&devs[0]); if(result) { printk(KERN_ERR "dsp: Can't init board!\n"); unregister_chrdev(DSP_MAJOR,"dsp"); return result; } return result;}voidcleanup_module(void){ dsp_reset(&devs[0]); free_irq(devs[0].irq, NULL); if(devs[0].dma <= 7) free_dma(devs[0].dma); irq2dev_map[devs[0].irq] = 0; unregister_chrdev(DSP_MAJOR,"dsp"); if(devs[0].base_addr) release_region(devs[0].base_addr, 0x20);}#endif /* MODULE */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -