rme96xx.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,862 行 · 第 1/4 页
C
1,862 行
*spdifrate = 0x1; if (readl(s->iobase + RME96xx_status_register) & RME96xx_ERF) { return -1; /* error condition */ } if (s->hw_rev == 15) { int x, y, ret; x = rme96xx_spdif_read_codec (s, 30); if (x != 0) y = 48000 * 64 / x; else y = 0; if (y > 30400 && y < 33600) {ret = 32000; *spdifrate = 0x7;} else if (y > 41900 && y < 46000) {ret = 44100; *spdifrate = 0x6;} else if (y > 46000 && y < 50400) {ret = 48000; *spdifrate = 0x5;} else if (y > 60800 && y < 67200) {ret = 64000; *spdifrate = 0x0;} else if (y > 83700 && y < 92000) {ret = 88200; *spdifrate = 0x4;} else if (y > 92000 && y < 100000) {ret = 96000; *spdifrate = 0x3;} else {ret = 0; *spdifrate = 0x1;} return ret; } rate_bits = readl(s->iobase + RME96xx_status_register) & RME96xx_F; switch (*spdifrate = rme96xx_decode_spdif_rate(rate_bits)) { case 0x7: return 32000; break; case 0x6: return 44100; break; case 0x5: return 48000; break; case 0x4: return 88200; break; case 0x3: return 96000; break; case 0x0: return 64000; break; default: /* was an ALSA warning ... snd_printk("%s: unknown S/PDIF input rate (bits = 0x%x)\n", s->card_name, rate_bits); */ return 0; break; }}/* end of code from ALSA card-rme9652.c *//* the hwbuf in the status register seems to have some jitter, to get rid of it, we first only let the numbers grow, to be on the secure side we subtract a certain amount RME96xx_BURSTBYTES from the resulting number *//* the function returns the hardware pointer in bytes */#define RME96xx_BURSTBYTES -64 /* bytes by which hwptr could be off */inline int rme96xx_gethwptr(rme96xx_info* s,int exact){ unsigned long flags; if (exact) { unsigned int hwp;/* the hwptr seems to be rather unreliable :(, so we don't use it */ spin_lock_irqsave(&s->lock,flags); hwp = readl(s->iobase + RME96xx_status_register) & 0xffc0; s->hwptr = (hwp < s->hwptr) ? s->hwptr : hwp;// s->hwptr = hwp; spin_unlock_irqrestore(&s->lock,flags); return (s->hwptr+RME96xx_BURSTBYTES) & ((s->fragsize<<1)-1); } return (s->hwbufid ? s->fragsize : 0);}inline void rme96xx_setlatency(rme96xx_info* s,int l){ s->latency = l; s->fragsize = 1<<(8+l); rme96xx_unset_ctrl(s,RME96xx_latency); rme96xx_set_ctrl(s,RME96xx_SET_LATENCY(l)); }static void rme96xx_clearbufs(struct dmabuf* dma){ int i,j; unsigned long flags; /* clear dmabufs */ for(i=0;i<devices;i++) { for (j=0;j<dma->outchannels + dma->mono;j++) memset(&dma->s->playbuf[(dma->outoffset + j)*RME96xx_DMA_MAX_SAMPLES], 0, RME96xx_DMA_MAX_SIZE); } spin_lock_irqsave(&dma->s->lock,flags); dma->writeptr = 0; dma->readptr = 0; spin_unlock_irqrestore(&dma->s->lock,flags);}static int rme96xx_startcard(rme96xx_info *s,int stop){ int i; unsigned long flags; COMM ("startcard"); if(s->control_register & RME96xx_IE){ /* disable interrupt first */ rme96xx_unset_ctrl( s,RME96xx_start_bit ); udelay(10); rme96xx_unset_ctrl( s,RME96xx_IE); spin_lock_irqsave(&s->lock,flags); /* timing is critical */ s->started = 0; spin_unlock_irqrestore(&s->lock,flags); if (stop) { COMM("Sound card stopped"); return 1; } } COMM ("interrupt disabled"); /* first initialize all pointers on card */ for(i=0;i<RME96xx_num_of_init_regs;i++){ writel(0,s->iobase + i); udelay(10); /* ?? */ } COMM ("regs cleaned"); spin_lock_irqsave(&s->lock,flags); /* timing is critical */ udelay(10); s->started = 1; s->hwptr = 0; spin_unlock_irqrestore(&s->lock,flags); rme96xx_set_ctrl( s, RME96xx_IE | RME96xx_start_bit); COMM("Sound card started"); return 1;}inline int rme96xx_getospace(struct dmabuf * dma, unsigned int hwp){ int cnt; int swptr; unsigned long flags; spin_lock_irqsave(&dma->s->lock,flags); swptr = dma->writeptr; cnt = (hwp - swptr); if (cnt < 0) { cnt = ((dma->s->fragsize<<1) - swptr); } spin_unlock_irqrestore(&dma->s->lock,flags); return cnt;}inline int rme96xx_getispace(struct dmabuf * dma, unsigned int hwp){ int cnt; int swptr; unsigned long flags; spin_lock_irqsave(&dma->s->lock,flags); swptr = dma->readptr; cnt = (hwp - swptr); if (cnt < 0) { cnt = ((dma->s->fragsize<<1) - swptr); } spin_unlock_irqrestore(&dma->s->lock,flags); return cnt;}inline int rme96xx_copyfromuser(struct dmabuf* dma,const char __user * buffer,int count,int hop){ int swptr = dma->writeptr; switch (dma->format) { case AFMT_S32_BLOCKED: { char __user * buf = (char __user *)buffer; int cnt = count/dma->outchannels; int i; for (i=0;i < dma->outchannels;i++) { char* hwbuf =(char*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES]; hwbuf+=swptr; if (copy_from_user(hwbuf,buf, cnt)) return -1; buf+=hop; } swptr+=cnt; break; } case AFMT_S16_LE: { int i,j; int cnt = count/dma->outchannels; for (i=0;i < dma->outchannels + dma->mono;i++) { short __user * sbuf = (short __user *)buffer + i*(!dma->mono); short* hwbuf =(short*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES]; hwbuf+=(swptr>>1); for (j=0;j<(cnt>>1);j++) { hwbuf++; /* skip the low 16 bits */ __get_user(*hwbuf++,sbuf++); sbuf+=(dma->outchannels-1); } } swptr += (cnt<<1); break; } default: printk(RME_MESS" unsupported format\n"); return -1; } /* switch */ swptr&=((dma->s->fragsize<<1) -1); dma->writeptr = swptr; return 0;}/* The count argument is the number of bytes */inline int rme96xx_copytouser(struct dmabuf* dma,const char __user* buffer,int count,int hop){ int swptr = dma->readptr; switch (dma->format) { case AFMT_S32_BLOCKED: { char __user * buf = (char __user *)buffer; int cnt = count/dma->inchannels; int i; for (i=0;i < dma->inchannels;i++) { char* hwbuf =(char*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES]; hwbuf+=swptr; if (copy_to_user(buf,hwbuf,cnt)) return -1; buf+=hop; } swptr+=cnt; break; } case AFMT_S16_LE: { int i,j; int cnt = count/dma->inchannels; for (i=0;i < dma->inchannels;i++) { short __user * sbuf = (short __user *)buffer + i; short* hwbuf =(short*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES]; hwbuf+=(swptr>>1); for (j=0;j<(cnt>>1);j++) { hwbuf++; __put_user(*hwbuf++,sbuf++); sbuf+=(dma->inchannels-1); } } swptr += (cnt<<1); break; } default: printk(RME_MESS" unsupported format\n"); return -1; } /* switch */ swptr&=((dma->s->fragsize<<1) -1); dma->readptr = swptr; return 0;}static irqreturn_t rme96xx_interrupt(int irq, void *dev_id, struct pt_regs *regs){ int i; rme96xx_info *s = (rme96xx_info *)dev_id; struct dmabuf *db; u32 status; unsigned long flags; status = readl(s->iobase + RME96xx_status_register); if (!(status & RME96xx_IRQ)) { return IRQ_NONE; } spin_lock_irqsave(&s->lock,flags); writel(0,s->iobase + RME96xx_irq_clear); s->hwbufid = (status & RME96xx_buffer_id)>>26; if ((status & 0xffc0) <= 256) s->hwptr = 0; for(i=0;i<devices;i++) { db = &(s->dma[i]); if(db->started > 0) wake_up(&(db->wait)); } spin_unlock_irqrestore(&s->lock,flags); return IRQ_HANDLED;}/*---------------------------------------------------------------------------- PCI detection and module initialization stuff ----------------------------------------------------------------------------*/void* busmaster_malloc(int size) { int pg; /* 2 s exponent of memory size */ char *buf; DBG(printk("kernel malloc pages ..\n")); for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); buf = (char *) __get_free_pages(GFP_KERNEL | GFP_DMA, pg); if (buf) { struct page* page, *last_page; page = virt_to_page(buf); last_page = virt_to_page(buf + (1 << pg)); DBG(printk("setting reserved bit\n")); while (page < last_page) { SetPageReserved(page); page++; } return buf; } DBG(printk("allocated %ld",(long)buf)); return NULL;}void busmaster_free(void* ptr,int size) { int pg; struct page* page, *last_page; if (ptr == NULL) return; for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); page = virt_to_page(ptr); last_page = page + (1 << pg); while (page < last_page) { ClearPageReserved(page); page++; } DBG(printk("freeing pages\n")); free_pages((unsigned long) ptr, pg); DBG(printk("done\n"));}/* initialize those parts of the info structure which are not pci detectable resources */static int rme96xx_dmabuf_init(rme96xx_info * s,struct dmabuf* dma,int ioffset,int ooffset) { init_MUTEX(&dma->open_sem); init_waitqueue_head(&dma->open_wait); init_waitqueue_head(&dma->wait); dma->s = s; dma->error = 0; dma->format = AFMT_S32_BLOCKED; dma->formatshift = 0; dma->inchannels = dma->outchannels = 1; dma->inoffset = ioffset; dma->outoffset = ooffset; dma->opened=0; dma->started=0; dma->mmapped=0; dma->open_mode=0; dma->mono=0; rme96xx_clearbufs(dma); return 0;}int rme96xx_init(rme96xx_info* s){ int i; int status; unsigned short rev; DBG(printk("%s\n", __FUNCTION__)); numcards++; s->magic = RME96xx_MAGIC; spin_lock_init(&s->lock); COMM ("setup busmaster memory") s->recbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL); s->playbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL); if (!s->recbuf || !s->playbuf) { printk(KERN_ERR RME_MESS" Unable to allocate busmaster memory\n"); return -ENODEV; } COMM ("setting rec and playbuffers") writel((u32) virt_to_bus(s->recbuf),s->iobase + RME96xx_rec_buffer); writel((u32) virt_to_bus(s->playbuf),s->iobase + RME96xx_play_buffer); COMM ("initializing control register") rme96xx_unset_ctrl(s,0xffffffff); rme96xx_set_ctrl(s,RME96xx_ctrl_init); COMM ("setup devices") for (i=0;i < devices;i++) { struct dmabuf * dma = &s->dma[i]; rme96xx_dmabuf_init(s,dma,2*i,2*i); } /* code from ALSA card-rme9652.c HP 20020201 */ /* Determine the h/w rev level of the card. This seems like a particularly kludgy way to encode it, but its what RME chose to do, so we follow them ... */ status = readl(s->iobase + RME96xx_status_register); if (rme96xx_decode_spdif_rate(status&RME96xx_F) == 1) { s->hw_rev = 15; } else { s->hw_rev = 11; } /* Differentiate between the standard Hammerfall, and the "Light", which does not have the expansion board. This method comes from information received from Mathhias Clausen at RME. Display the EEPROM and h/w revID where relevant. */ pci_read_config_word(s->pcidev, PCI_CLASS_REVISION, &rev); switch (rev & 0xff) { case 8: /* original eprom */ if (s->hw_rev == 15) { s->card_name = "RME Digi9636 (Rev 1.5)"; } else {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?