--- linux-old/include/asm-mips/au1xxx_dbdma.h 2006-05-09 18:24:17.000000000 +0200 +++ linux/include/asm-mips/au1xxx_dbdma.h 2006-05-09 14:05:48.000000000 +0200 @@ -34,6 +34,8 @@ #ifndef _AU1000_DBDMA_H_ #define _AU1000_DBDMA_H_ +#include + #ifndef _LANGUAGE_ASSEMBLY /* The DMA base addresses. @@ -43,7 +45,7 @@ #define DDMA_GLOBAL_BASE 0xb4003000 #define DDMA_CHANNEL_BASE 0xb4002000 -typedef struct dbdma_global { +typedef volatile struct dbdma_global { u32 ddma_config; u32 ddma_intstat; u32 ddma_throttle; @@ -60,7 +62,7 @@ /* The structure of a DMA Channel. */ -typedef struct au1xxx_dma_channel { +typedef volatile struct au1xxx_dma_channel { u32 ddma_cfg; /* See below */ u32 ddma_desptr; /* 32-byte aligned pointer to descriptor */ u32 ddma_statptr; /* word aligned pointer to status word */ @@ -96,7 +98,7 @@ /* "Standard" DDMA Descriptor. * Must be 32-byte aligned. */ -typedef struct au1xxx_ddma_desc { +typedef volatile struct au1xxx_ddma_desc { u32 dscr_cmd0; /* See below */ u32 dscr_cmd1; /* See below */ u32 dscr_source0; /* source phys address */ @@ -105,6 +107,12 @@ u32 dscr_dest1; /* See below */ u32 dscr_stat; /* completion status */ u32 dscr_nxtptr; /* Next descriptor pointer (mostly) */ + /* First 32bytes are HW specific!!! + Lets have some SW data following.. make sure its 32bytes + */ + u32 sw_status; + u32 sw_context; + u32 sw_reserved[6]; } au1x_ddma_desc_t; #define DSCR_CMD0_V (1 << 31) /* Descriptor valid */ @@ -123,6 +131,8 @@ #define DSCR_CMD0_CV (0x1 << 2) /* Clear Valid when done */ #define DSCR_CMD0_ST_MASK (0x3 << 0) /* Status instruction */ +#define SW_STATUS_INUSE (1<<0) + /* Command 0 device IDs. */ #ifdef CONFIG_SOC_AU1550 @@ -169,8 +179,8 @@ #define DSCR_CMD0_SDMS_RX0 9 #define DSCR_CMD0_SDMS_TX1 10 #define DSCR_CMD0_SDMS_RX1 11 -#define DSCR_CMD0_AES_TX 12 -#define DSCR_CMD0_AES_RX 13 +#define DSCR_CMD0_AES_TX 13 +#define DSCR_CMD0_AES_RX 12 #define DSCR_CMD0_PSC0_TX 14 #define DSCR_CMD0_PSC0_RX 15 #define DSCR_CMD0_PSC1_TX 16 @@ -189,6 +199,10 @@ #define DSCR_CMD0_THROTTLE 30 #define DSCR_CMD0_ALWAYS 31 #define DSCR_NDEV_IDS 32 +/* THis macro is used to find/create custom device types */ +#define DSCR_DEV2CUSTOM_ID(x,d) (((((x)&0xFFFF)<<8)|0x32000000)|((d)&0xFF)) +#define DSCR_CUSTOM2DEV_ID(x) ((x)&0xFF) + #define DSCR_CMD0_SID(x) (((x) & 0x1f) << 25) #define DSCR_CMD0_DID(x) (((x) & 0x1f) << 20) @@ -277,6 +291,43 @@ */ #define NUM_DBDMA_CHANS 16 +/* + * Ddma API definitions + * FIXME: may not fit to this header file + */ +typedef struct dbdma_device_table { + u32 dev_id; + u32 dev_flags; + u32 dev_tsize; + u32 dev_devwidth; + u32 dev_physaddr; /* If FIFO */ + u32 dev_intlevel; + u32 dev_intpolarity; +} dbdev_tab_t; + + +typedef struct dbdma_chan_config { + spinlock_t lock; + + u32 chan_flags; + u32 chan_index; + dbdev_tab_t *chan_src; + dbdev_tab_t *chan_dest; + au1x_dma_chan_t *chan_ptr; + au1x_ddma_desc_t *chan_desc_base; + au1x_ddma_desc_t *get_ptr, *put_ptr, *cur_ptr; + void *chan_callparam; + void (*chan_callback)(int, void *, struct pt_regs *); +} chan_tab_t; + +#define DEV_FLAGS_INUSE (1 << 0) +#define DEV_FLAGS_ANYUSE (1 << 1) +#define DEV_FLAGS_OUT (1 << 2) +#define DEV_FLAGS_IN (1 << 3) +#define DEV_FLAGS_BURSTABLE (1 << 4) +#define DEV_FLAGS_SYNC (1 << 5) +/* end Ddma API definitions */ + /* External functions for drivers to use. */ /* Use this to allocate a dbdma channel. The device ids are one of the @@ -299,8 +350,8 @@ /* Put buffers on source/destination descriptors. */ -u32 au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes); -u32 au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes); +u32 _au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags); +u32 _au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags); /* Get a buffer from the destination descriptor. */ @@ -314,5 +365,29 @@ void au1xxx_dbdma_chan_free(u32 chanid); void au1xxx_dbdma_dump(u32 chanid); +u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr ); + +u32 au1xxx_ddma_add_device( dbdev_tab_t *dev ); +void * au1xxx_ddma_get_nextptr_virt(au1x_ddma_desc_t *dp); + +/* + Some compatibilty macros -- + Needed to make changes to API without breaking existing drivers +*/ +#define au1xxx_dbdma_put_source(chanid,buf,nbytes)_au1xxx_dbdma_put_source(chanid, buf, nbytes, DDMA_FLAGS_IE) +#define au1xxx_dbdma_put_source_flags(chanid,buf,nbytes,flags) _au1xxx_dbdma_put_source(chanid, buf, nbytes, flags) +#define put_source_flags(chanid,buf,nbytes,flags) au1xxx_dbdma_put_source_flags(chanid,buf,nbytes,flags) + + +#define au1xxx_dbdma_put_dest(chanid,buf,nbytes) _au1xxx_dbdma_put_dest(chanid, buf, nbytes, DDMA_FLAGS_IE) +#define au1xxx_dbdma_put_dest_flags(chanid,buf,nbytes,flags) _au1xxx_dbdma_put_dest(chanid, buf, nbytes, flags) +#define put_dest_flags(chanid,buf,nbytes,flags) au1xxx_dbdma_put_dest_flags(chanid,buf,nbytes,flags) + +/* + * Flags for the put_source/put_dest functions. + */ +#define DDMA_FLAGS_IE (1<<0) +#define DDMA_FLAGS_NOIE (1<<1) + #endif /* _LANGUAGE_ASSEMBLY */ #endif /* _AU1000_DBDMA_H_ */ --- linux-old/arch/mips/au1000/common/dbdma.c 2006-05-09 18:23:18.000000000 +0200 +++ linux/arch/mips/au1000/common/dbdma.c 2006-05-09 14:04:44.000000000 +0200 @@ -30,6 +30,7 @@ * */ +#include #include #include #include @@ -37,13 +38,14 @@ #include #include #include +#include +#include #include #include #include -#include -#if 1 // defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) +#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) /* * The Descriptor Based DMA supports up to 16 channels. @@ -62,37 +64,10 @@ */ #define ALIGN_ADDR(x, a) ((((u32)(x)) + (a-1)) & ~(a-1)) -static volatile dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE; -static int dbdma_initialized; +static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE; +static int dbdma_initialized=0; static void au1xxx_dbdma_init(void); -typedef struct dbdma_device_table { - u32 dev_id; - u32 dev_flags; - u32 dev_tsize; - u32 dev_devwidth; - u32 dev_physaddr; /* If FIFO */ - u32 dev_intlevel; - u32 dev_intpolarity; -} dbdev_tab_t; - -typedef struct dbdma_chan_config { - u32 chan_flags; - u32 chan_index; - dbdev_tab_t *chan_src; - dbdev_tab_t *chan_dest; - au1x_dma_chan_t *chan_ptr; - au1x_ddma_desc_t *chan_desc_base; - au1x_ddma_desc_t *get_ptr, *put_ptr, *cur_ptr; - void *chan_callparam; - void (*chan_callback)(int, void *, struct pt_regs *); -} chan_tab_t; - -#define DEV_FLAGS_INUSE (1 << 0) -#define DEV_FLAGS_ANYUSE (1 << 1) -#define DEV_FLAGS_OUT (1 << 2) -#define DEV_FLAGS_IN (1 << 3) - static dbdev_tab_t dbdev_tab[] = { #ifdef CONFIG_SOC_AU1550 /* UARTS */ @@ -158,25 +133,25 @@ { DSCR_CMD0_MAE_BOTH, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, { DSCR_CMD0_LCD, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_SDMS_TX0, DEV_FLAGS_OUT, 4, 8, 0x10600000, 0, 0 }, + { DSCR_CMD0_SDMS_RX0, DEV_FLAGS_IN, 4, 8, 0x10600004, 0, 0 }, + { DSCR_CMD0_SDMS_TX1, DEV_FLAGS_OUT, 4, 8, 0x10680000, 0, 0 }, + { DSCR_CMD0_SDMS_RX1, DEV_FLAGS_IN, 4, 8, 0x10680004, 0, 0 }, - { DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_AES_RX, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_AES_RX, DEV_FLAGS_IN , 4, 32, 0x10300008, 0, 0 }, + { DSCR_CMD0_AES_TX, DEV_FLAGS_OUT, 4, 32, 0x10300004, 0, 0 }, - { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 0, 0x11a0001c, 0, 0 }, - { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 0, 0x11a0001c, 0, 0 }, + { DSCR_CMD0_PSC0_TX, DEV_FLAGS_OUT, 0, 16, 0x11a0001c, 0, 0 }, + { DSCR_CMD0_PSC0_RX, DEV_FLAGS_IN, 0, 16, 0x11a0001c, 0, 0 }, { DSCR_CMD0_PSC0_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 0, 0x11b0001c, 0, 0 }, - { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 0, 0x11b0001c, 0, 0 }, + { DSCR_CMD0_PSC1_TX, DEV_FLAGS_OUT, 0, 16, 0x11b0001c, 0, 0 }, + { DSCR_CMD0_PSC1_RX, DEV_FLAGS_IN, 0, 16, 0x11b0001c, 0, 0 }, { DSCR_CMD0_PSC1_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, - { DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, + { DSCR_CMD0_CIM_RXA, DEV_FLAGS_IN, 0, 32, 0x14004020, 0, 0 }, + { DSCR_CMD0_CIM_RXB, DEV_FLAGS_IN, 0, 32, 0x14004040, 0, 0 }, + { DSCR_CMD0_CIM_RXC, DEV_FLAGS_IN, 0, 32, 0x14004060, 0, 0 }, { DSCR_CMD0_CIM_SYNC, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, { DSCR_CMD0_NAND_FLASH, DEV_FLAGS_IN, 0, 0, 0x00000000, 0, 0 }, @@ -185,6 +160,24 @@ { DSCR_CMD0_THROTTLE, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, { DSCR_CMD0_ALWAYS, DEV_FLAGS_ANYUSE, 0, 0, 0x00000000, 0, 0 }, + + /* Provide 16 user definable device types */ + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, }; #define DBDEV_TAB_SIZE (sizeof(dbdev_tab) / sizeof(dbdev_tab_t)) @@ -204,6 +197,36 @@ return NULL; } +void * au1xxx_ddma_get_nextptr_virt(au1x_ddma_desc_t *dp) +{ + return phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); +} +EXPORT_SYMBOL(au1xxx_ddma_get_nextptr_virt); + +u32 +au1xxx_ddma_add_device(dbdev_tab_t *dev) +{ + u32 ret = 0; + dbdev_tab_t *p=NULL; + static u16 new_id=0x1000; + + p = find_dbdev_id(0); + if ( NULL != p ) + { + memcpy(p, dev, sizeof(dbdev_tab_t)); + p->dev_id = DSCR_DEV2CUSTOM_ID(new_id,dev->dev_id); + ret = p->dev_id; + new_id++; +#if 0 + printk("add_device: id:%x flags:%x padd:%x\n", + p->dev_id, p->dev_flags, p->dev_physaddr ); +#endif + } + + return ret; +} +EXPORT_SYMBOL(au1xxx_ddma_add_device); + /* Allocate a channel and return a non-zero descriptor if successful. */ u32 @@ -216,7 +239,7 @@ int i; dbdev_tab_t *stp, *dtp; chan_tab_t *ctp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; /* We do the intialization on the first channel allocation. * We have to wait because of the interrupt handler initialization @@ -226,9 +249,6 @@ au1xxx_dbdma_init(); dbdma_initialized = 1; - if ((srcid > DSCR_NDEV_IDS) || (destid > DSCR_NDEV_IDS)) - return 0; - if ((stp = find_dbdev_id(srcid)) == NULL) return 0; if ((dtp = find_dbdev_id(destid)) == NULL) return 0; @@ -240,7 +260,7 @@ spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); if (!(stp->dev_flags & DEV_FLAGS_INUSE) || (stp->dev_flags & DEV_FLAGS_ANYUSE)) { - /* Got source */ + /* Got source */ stp->dev_flags |= DEV_FLAGS_INUSE; if (!(dtp->dev_flags & DEV_FLAGS_INUSE) || (dtp->dev_flags & DEV_FLAGS_ANYUSE)) { @@ -270,9 +290,8 @@ /* If kmalloc fails, it is caught below same * as a channel not available. */ - ctp = (chan_tab_t *)kmalloc(sizeof(chan_tab_t), GFP_KERNEL); + ctp = kmalloc(sizeof(chan_tab_t), GFP_KERNEL); chan_tab_ptr[i] = ctp; - ctp->chan_index = chan = i; break; } } @@ -280,10 +299,11 @@ if (ctp != NULL) { memset(ctp, 0, sizeof(chan_tab_t)); + ctp->chan_index = chan = i; dcp = DDMA_CHANNEL_BASE; dcp += (0x0100 * chan); ctp->chan_ptr = (au1x_dma_chan_t *)dcp; - cp = (volatile au1x_dma_chan_t *)dcp; + cp = (au1x_dma_chan_t *)dcp; ctp->chan_src = stp; ctp->chan_dest = dtp; ctp->chan_callback = callback; @@ -300,6 +320,9 @@ i |= DDMA_CFG_DED; if (dtp->dev_intpolarity) i |= DDMA_CFG_DP; + if ((stp->dev_flags & DEV_FLAGS_SYNC) || + (dtp->dev_flags & DEV_FLAGS_SYNC)) + i |= DDMA_CFG_SYNC; cp->ddma_cfg = i; au_sync(); @@ -310,14 +333,14 @@ rv = (u32)(&chan_tab_ptr[chan]); } else { - /* Release devices. - */ + /* Release devices */ stp->dev_flags &= ~DEV_FLAGS_INUSE; dtp->dev_flags &= ~DEV_FLAGS_INUSE; } } return rv; } +EXPORT_SYMBOL(au1xxx_dbdma_chan_alloc); /* Set the device width if source or destination is a FIFO. * Should be 8, 16, or 32 bits. @@ -345,6 +368,7 @@ return rv; } +EXPORT_SYMBOL(au1xxx_dbdma_set_devwidth); /* Allocate a descriptor ring, initializing as much as possible. */ @@ -371,10 +395,11 @@ * and if we try that first we are likely to not waste larger * slabs of memory. */ - desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), GFP_KERNEL); + desc_base = (u32)kmalloc(entries * sizeof(au1x_ddma_desc_t), + GFP_KERNEL|GFP_DMA); if (desc_base == 0) return 0; - + if (desc_base & 0x1f) { /* Lost....do it again, allocate extra, and round * the address base. @@ -382,7 +407,7 @@ kfree((const void *)desc_base); i = entries * sizeof(au1x_ddma_desc_t); i += (sizeof(au1x_ddma_desc_t) - 1); - if ((desc_base = (u32)kmalloc(i, GFP_KERNEL)) == 0) + if ((desc_base = (u32)kmalloc(i, GFP_KERNEL|GFP_DMA)) == 0) return 0; desc_base = ALIGN_ADDR(desc_base, sizeof(au1x_ddma_desc_t)); @@ -404,7 +429,13 @@ cmd0 |= DSCR_CMD0_SID(srcid); cmd0 |= DSCR_CMD0_DID(destid); cmd0 |= DSCR_CMD0_IE | DSCR_CMD0_CV; - cmd0 |= DSCR_CMD0_ST(DSCR_CMD0_ST_CURRENT); + cmd0 |= DSCR_CMD0_ST(DSCR_CMD0_ST_NOCHANGE); + + /* is it mem to mem transfer? */ + if(((DSCR_CUSTOM2DEV_ID(srcid) == DSCR_CMD0_THROTTLE) || (DSCR_CUSTOM2DEV_ID(srcid) == DSCR_CMD0_ALWAYS)) && + ((DSCR_CUSTOM2DEV_ID(destid) == DSCR_CMD0_THROTTLE) || (DSCR_CUSTOM2DEV_ID(destid) == DSCR_CMD0_ALWAYS))) { + cmd0 |= DSCR_CMD0_MEM; + } switch (stp->dev_devwidth) { case 8: @@ -462,9 +493,14 @@ /* If source input is fifo, set static address. */ if (stp->dev_flags & DEV_FLAGS_IN) { - src0 = stp->dev_physaddr; + if ( stp->dev_flags & DEV_FLAGS_BURSTABLE ) + src1 |= DSCR_SRC1_SAM(DSCR_xAM_BURST); + else src1 |= DSCR_SRC1_SAM(DSCR_xAM_STATIC); + } + if (stp->dev_physaddr) + src0 = stp->dev_physaddr; /* Set up dest1. For now, assume no stride and increment. * A channel attribute update can change this later. @@ -488,10 +524,18 @@ /* If destination output is fifo, set static address. */ if (dtp->dev_flags & DEV_FLAGS_OUT) { - dest0 = dtp->dev_physaddr; + if ( dtp->dev_flags & DEV_FLAGS_BURSTABLE ) + dest1 |= DSCR_DEST1_DAM(DSCR_xAM_BURST); + else dest1 |= DSCR_DEST1_DAM(DSCR_xAM_STATIC); } - + if (dtp->dev_physaddr) + dest0 = dtp->dev_physaddr; + +#if 0 + printk("did:%x sid:%x cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n", + dtp->dev_id, stp->dev_id, cmd0, cmd1, src0, src1, dest0, dest1 ); +#endif for (i=0; idscr_cmd0 = cmd0; dp->dscr_cmd1 = cmd1; @@ -500,10 +544,12 @@ dp->dscr_dest0 = dest0; dp->dscr_dest1 = dest1; dp->dscr_stat = 0; + dp->sw_context = 0; + dp->sw_status = 0; dp->dscr_nxtptr = DSCR_NXTPTR(virt_to_phys(dp + 1)); dp++; } - + /* Make last descrptor point to the first. */ dp--; @@ -512,13 +558,14 @@ return (u32)(ctp->chan_desc_base); } +EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc); /* Put a source buffer into the DMA ring. * This updates the source pointer and byte count. Normally used * for memory to fifo transfers. */ u32 -au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes) +_au1xxx_dbdma_put_source(u32 chanid, void *buf, int nbytes, u32 flags) { chan_tab_t *ctp; au1x_ddma_desc_t *dp; @@ -540,14 +587,30 @@ if (dp->dscr_cmd0 & DSCR_CMD0_V) { return 0; } - + /* Load up buffer address and byte count. */ dp->dscr_source0 = virt_to_phys(buf); dp->dscr_cmd1 = nbytes; - dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ - ctp->chan_ptr->ddma_dbell = 0xffffffff; /* Make it go */ - + /* Check flags */ + if (flags & DDMA_FLAGS_IE) + dp->dscr_cmd0 |= DSCR_CMD0_IE; + if (flags & DDMA_FLAGS_NOIE) + dp->dscr_cmd0 &= ~DSCR_CMD0_IE; + + /* + * There is an errata on the Au1200/Au1550 parts that could result + * in "stale" data being DMA'd. It has to do with the snoop logic on + * the dache eviction buffer. NONCOHERENT_IO is on by default for + * these parts. If it is fixedin the future, these dma_cache_inv will + * just be nothing more than empty macros. See io.h. + * */ + dma_cache_wback_inv((unsigned long)buf, nbytes); + dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ + au_sync(); + dma_cache_wback_inv((unsigned long)dp, sizeof(dp)); + ctp->chan_ptr->ddma_dbell = 0; + /* Get next descriptor pointer. */ ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); @@ -556,13 +619,14 @@ */ return nbytes; } +EXPORT_SYMBOL(_au1xxx_dbdma_put_source); /* Put a destination buffer into the DMA ring. * This updates the destination pointer and byte count. Normally used * to place an empty buffer into the ring for fifo to memory transfers. */ u32 -au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes) +_au1xxx_dbdma_put_dest(u32 chanid, void *buf, int nbytes, u32 flags) { chan_tab_t *ctp; au1x_ddma_desc_t *dp; @@ -581,15 +645,38 @@ /* If the descriptor is valid, we are way ahead of the DMA * engine, so just return an error condition. */ - if (dp->dscr_cmd0 & DSCR_CMD0_V) + if (dp->dscr_cmd0 & DSCR_CMD0_V) { return 0; - - /* Load up buffer address and byte count. - */ + } + + /* Load up buffer address and byte count */ + + /* Check flags */ + if (flags & DDMA_FLAGS_IE) + dp->dscr_cmd0 |= DSCR_CMD0_IE; + if (flags & DDMA_FLAGS_NOIE) + dp->dscr_cmd0 &= ~DSCR_CMD0_IE; + dp->dscr_dest0 = virt_to_phys(buf); dp->dscr_cmd1 = nbytes; +#if 0 + printk("cmd0:%x cmd1:%x source0:%x source1:%x dest0:%x dest1:%x\n", + dp->dscr_cmd0, dp->dscr_cmd1, dp->dscr_source0, + dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1 ); +#endif + /* + * There is an errata on the Au1200/Au1550 parts that could result in + * "stale" data being DMA'd. It has to do with the snoop logic on the + * dache eviction buffer. NONCOHERENT_IO is on by default for these + * parts. If it is fixedin the future, these dma_cache_inv will just + * be nothing more than empty macros. See io.h. + * */ + dma_cache_inv((unsigned long)buf,nbytes); dp->dscr_cmd0 |= DSCR_CMD0_V; /* Let it rip */ - + au_sync(); + dma_cache_wback_inv((unsigned long)dp, sizeof(dp)); + ctp->chan_ptr->ddma_dbell = 0; + /* Get next descriptor pointer. */ ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); @@ -598,6 +685,7 @@ */ return nbytes; } +EXPORT_SYMBOL(_au1xxx_dbdma_put_dest); /* Get a destination buffer into the DMA ring. * Normally used to get a full buffer from the ring during fifo @@ -625,29 +713,31 @@ /* If the descriptor is valid, we are way ahead of the DMA * engine, so just return an error condition. */ - if (dp->dscr_cmd0 & DSCR_CMD0_V) + if (dp->dscr_cmd0 & DSCR_CMD0_V) { return 0; - + } + /* Return buffer address and byte count. */ *buf = (void *)(phys_to_virt(dp->dscr_dest0)); *nbytes = dp->dscr_cmd1; rv = dp->dscr_stat; - + /* Get next descriptor pointer. */ ctp->get_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); /* return something not zero. */ - return rv; + return *nbytes; } +EXPORT_SYMBOL(au1xxx_dbdma_get_dest); void au1xxx_dbdma_stop(u32 chanid) { chan_tab_t *ctp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; int halt_timeout = 0; ctp = *((chan_tab_t **)chanid); @@ -667,6 +757,7 @@ cp->ddma_stat |= (DDMA_STAT_DB | DDMA_STAT_V); au_sync(); } +EXPORT_SYMBOL(au1xxx_dbdma_stop); /* Start using the current descriptor pointer. If the dbdma encounters * a not valid descriptor, it will stop. In this case, we can just @@ -676,17 +767,17 @@ au1xxx_dbdma_start(u32 chanid) { chan_tab_t *ctp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; ctp = *((chan_tab_t **)chanid); - cp = ctp->chan_ptr; cp->ddma_desptr = virt_to_phys(ctp->cur_ptr); cp->ddma_cfg |= DDMA_CFG_EN; /* Enable channel */ au_sync(); - cp->ddma_dbell = 0xffffffff; /* Make it go */ + cp->ddma_dbell = 0; au_sync(); } +EXPORT_SYMBOL(au1xxx_dbdma_start); void au1xxx_dbdma_reset(u32 chanid) @@ -705,15 +796,21 @@ do { dp->dscr_cmd0 &= ~DSCR_CMD0_V; + /* reset our SW status -- this is used to determine + * if a descriptor is in use by upper level SW. Since + * posting can reset 'V' bit. + */ + dp->sw_status = 0; dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); } while (dp != ctp->chan_desc_base); } +EXPORT_SYMBOL(au1xxx_dbdma_reset); u32 au1xxx_get_dma_residue(u32 chanid) { chan_tab_t *ctp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; u32 rv; ctp = *((chan_tab_t **)chanid); @@ -726,6 +823,7 @@ return rv; } +EXPORT_SYMBOL(au1xxx_get_dma_residue); void au1xxx_dbdma_chan_free(u32 chanid) @@ -739,35 +837,35 @@ au1xxx_dbdma_stop(chanid); - if (ctp->chan_desc_base != NULL) - kfree(ctp->chan_desc_base); - + kfree((void *)ctp->chan_desc_base); + stp->dev_flags &= ~DEV_FLAGS_INUSE; dtp->dev_flags &= ~DEV_FLAGS_INUSE; chan_tab_ptr[ctp->chan_index] = NULL; kfree(ctp); } +EXPORT_SYMBOL(au1xxx_dbdma_chan_free); -static void +static irqreturn_t dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - u32 intstat; - u32 chan_index; + u32 intstat; + u32 chan_index; chan_tab_t *ctp; au1x_ddma_desc_t *dp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; intstat = dbdma_gptr->ddma_intstat; au_sync(); chan_index = au_ffs(intstat) - 1; ctp = chan_tab_ptr[chan_index]; cp = ctp->chan_ptr; dp = ctp->cur_ptr; /* Reset interrupt. - */ + */ cp->ddma_irq = 0; au_sync(); @@ -775,18 +875,28 @@ (ctp->chan_callback)(irq, ctp->chan_callparam, regs); ctp->cur_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); - + + return IRQ_RETVAL(1); } -static void -au1xxx_dbdma_init(void) +static void au1xxx_dbdma_init(void) { + int irq_nr; + dbdma_gptr->ddma_config = 0; dbdma_gptr->ddma_throttle = 0; dbdma_gptr->ddma_inten = 0xffff; au_sync(); - if (request_irq(AU1550_DDMA_INT, dbdma_interrupt, SA_INTERRUPT, +#if defined(CONFIG_SOC_AU1550) + irq_nr = AU1550_DDMA_INT; +#elif defined(CONFIG_SOC_AU1200) + irq_nr = AU1200_DDMA_INT; +#else + #error Unknown Au1x00 SOC +#endif + + if (request_irq(irq_nr, dbdma_interrupt, SA_INTERRUPT, "Au1xxx dbdma", (void *)dbdma_gptr)) printk("Can't get 1550 dbdma irq"); } @@ -797,7 +907,8 @@ chan_tab_t *ctp; au1x_ddma_desc_t *dp; dbdev_tab_t *stp, *dtp; - volatile au1x_dma_chan_t *cp; + au1x_dma_chan_t *cp; + u32 i = 0; ctp = *((chan_tab_t **)chanid); stp = ctp->chan_src; @@ -809,7 +920,7 @@ printk("desc base %x, get %x, put %x, cur %x\n", (u32)(ctp->chan_desc_base), (u32)(ctp->get_ptr), (u32)(ctp->put_ptr), (u32)(ctp->cur_ptr)); - + printk("dbdma chan %x\n", (u32)cp); printk("cfg %08x, desptr %08x, statptr %08x\n", cp->ddma_cfg, cp->ddma_desptr, cp->ddma_statptr); @@ -822,28 +933,65 @@ dp = ctp->chan_desc_base; do { - printk("dp %08x, cmd0 %08x, cmd1 %08x\n", - (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1); - printk("src0 %08x, src1 %08x, dest0 %08x\n", - dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0); - printk("dest1 %08x, stat %08x, nxtptr %08x\n", - dp->dscr_dest1, dp->dscr_stat, dp->dscr_nxtptr); + printk("Dp[%d]= %08x, cmd0 %08x, cmd1 %08x\n", + i++, (u32)dp, dp->dscr_cmd0, dp->dscr_cmd1); + printk("src0 %08x, src1 %08x, dest0 %08x, dest1 %08x\n", + dp->dscr_source0, dp->dscr_source1, dp->dscr_dest0, dp->dscr_dest1); + printk("stat %08x, nxtptr %08x\n", + dp->dscr_stat, dp->dscr_nxtptr); dp = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); } while (dp != ctp->chan_desc_base); } +EXPORT_SYMBOL(au1xxx_dbdma_dump); +/* Put a descriptor into the DMA ring. + * This updates the source/destination pointers and byte count. + */ +u32 +au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr ) +{ + chan_tab_t *ctp; + au1x_ddma_desc_t *dp; + u32 nbytes=0; -EXPORT_SYMBOL(au1xxx_dbdma_dump); -EXPORT_SYMBOL(au1xxx_dbdma_put_source); -EXPORT_SYMBOL(au1xxx_dbdma_put_dest); -EXPORT_SYMBOL(au1xxx_dbdma_ring_alloc); -EXPORT_SYMBOL(au1xxx_dbdma_start); -EXPORT_SYMBOL(au1xxx_dbdma_get_dest); -EXPORT_SYMBOL(au1xxx_dbdma_chan_alloc); -EXPORT_SYMBOL(au1xxx_get_dma_residue); -EXPORT_SYMBOL(au1xxx_dbdma_set_devwidth); -EXPORT_SYMBOL(au1xxx_dbdma_chan_free); -EXPORT_SYMBOL(au1xxx_dbdma_reset); + /* I guess we could check this to be within the + * range of the table...... + */ + ctp = *((chan_tab_t **)chanid); -#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */ + /* We should have multiple callers for a particular channel, + * an interrupt doesn't affect this pointer nor the descriptor, + * so no locking should be needed. + */ + dp = ctp->put_ptr; + + /* If the descriptor is valid, we are way ahead of the DMA + * engine, so just return an error condition. + */ + if (dp->dscr_cmd0 & DSCR_CMD0_V) + return 0; + /* Load up buffer addresses and byte count. + */ + dp->dscr_dest0 = dscr->dscr_dest0; + dp->dscr_source0 = dscr->dscr_source0; + dp->dscr_dest1 = dscr->dscr_dest1; + dp->dscr_source1 = dscr->dscr_source1; + dp->dscr_cmd1 = dscr->dscr_cmd1; + nbytes = dscr->dscr_cmd1; + /* Allow the caller to specifiy if an interrupt is generated */ + dp->dscr_cmd0 &= ~DSCR_CMD0_IE; + dp->dscr_cmd0 |= dscr->dscr_cmd0 | DSCR_CMD0_V; + ctp->chan_ptr->ddma_dbell = 0; + + /* Get next descriptor pointer. + */ + ctp->put_ptr = phys_to_virt(DSCR_GET_NXTPTR(dp->dscr_nxtptr)); + + /* return something not zero. + */ + return nbytes; +} +EXPORT_SYMBOL(au1xxx_dbdma_put_dscr); + +#endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */ --- linux-old/drivers/sound/au1550_psc.c 2006-05-09 14:49:35.000000000 +0200 +++ linux/drivers/sound/au1550_psc.c 2006-05-09 18:19:01.000000000 +0200 @@ -82,6 +83,11 @@ #define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg) #define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg) +#ifdef AU1000_VERBOSE_DEBUG +#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg) +#else +#define dbg(format, arg...) +#endif /* AU1000_VERBOSE_DEBUG */ /* Boot options * 0 = no VRA, 1 = use VRA if codec supports it @@ -127,7 +129,7 @@ unsigned fragshift; void *nextIn; void *nextOut; - int count; + volatile int count; unsigned total_bytes; unsigned error; wait_queue_head_t wait; @@ -198,7 +200,7 @@ struct au1550_state *s = (struct au1550_state *)codec->private_data; unsigned long flags; u32 cmd, val; - u16 data; + u16 data=0; int i; spin_lock_irqsave(&s->lock, flags); @@ -210,26 +212,21 @@ break; } if (i == POLL_COUNT) - err("rdcodec: codec cmd pending expired!"); + err("rdcodec: codec cmd pending expired! %i %i", val, addr); + + val = au_readl(PSC_AC97EVNT); + if (val & PSC_AC97EVNT_CD) { + err("rdcodec: command done is set! %i %i", val, addr); + au_readl(PSC_AC97CDC); // manual says: you must read CDC[DATA] before resetting EVNT[CD], if command was read; and we don't know here what the last command was + au_sync(); + au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT); + } cmd = (u32)PSC_AC97CDC_INDX(addr); cmd |= PSC_AC97CDC_RD; /* read command */ au_writel(cmd, PSC_AC97CDC); au_sync(); - /* now wait for the data - */ - for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (!(val & PSC_AC97STAT_CP)) - break; - } - if (i == POLL_COUNT) { - err("rdcodec: read poll expired!"); - return 0; - } - /* wait for command done? */ for (i = 0; i < POLL_COUNT; i++) { @@ -239,8 +236,8 @@ break; } if (i == POLL_COUNT) { - err("rdcodec: read cmdwait expired!"); - return 0; + err("rdcodec: read cmdwait expired! %i %i", val, addr); + goto rcodec_out; } data = au_readl(PSC_AC97CDC) & 0xffff; @@ -251,8 +248,11 @@ au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT); au_sync(); + rcodec_out: spin_unlock_irqrestore(&s->lock, flags); + dbg("rdcodec %x -> %x", addr, data); + return data; } @@ -274,7 +274,15 @@ break; } if (i == POLL_COUNT) - err("wrcodec: codec cmd pending expired!"); + err("wrcodec: codec cmd pending expired! %i %i", val, addr); + + val = au_readl(PSC_AC97EVNT); + if (val & PSC_AC97EVNT_CD) { + err("wrcodec: command done is set! %i %i", val, addr); + au_readl(PSC_AC97CDC); // manual says: you must read CDC[DATA] before resetting EVNT[CD], if command was read; and we don't know here what the last command was + au_sync(); + au_writel(PSC_AC97EVNT_CD, PSC_AC97EVNT); + } cmd = (u32)PSC_AC97CDC_INDX(addr); cmd |= (u32)data; @@ -282,22 +290,13 @@ au_sync(); for (i = 0; i < POLL_COUNT; i++) { - val = au_readl(PSC_AC97STAT); - au_sync(); - if (!(val & PSC_AC97STAT_CP)) - break; - } - if (i == POLL_COUNT) - err("wrcodec: codec cmd pending expired!"); - - for (i = 0; i < POLL_COUNT; i++) { val = au_readl(PSC_AC97EVNT); au_sync(); if (val & PSC_AC97EVNT_CD) break; } if (i == POLL_COUNT) - err("wrcodec: read cmdwait expired!"); + err("wrcodec: read cmdwait expired! %i %i", val, addr); /* Clear command done event. */ @@ -305,6 +304,8 @@ au_sync(); spin_unlock_irqrestore(&s->lock, flags); + + dbg("wrcodec %x -> %x done", data, addr); } static void @@ -392,7 +393,7 @@ adc_rate = rdcodec(s->codec, AC97_PCM_LR_ADC_RATE); #ifdef AU1000_VERBOSE_DEBUG - dbg(__FUNCTION__ ": set to %d Hz", adc_rate); + dbg("%s : set to %d Hz", __FUNCTION__, adc_rate); #endif /* some codec's don't allow unequal DAC and ADC rates, in which case @@ -452,7 +453,7 @@ dac_rate = rdcodec(s->codec, AC97_PCM_FRONT_DAC_RATE); #ifdef AU1000_VERBOSE_DEBUG - dbg(__FUNCTION__ ": set to %d Hz", dac_rate); + dbg("%s : set to %d Hz", __FUNCTION__, dac_rate); #endif /* some codec's don't allow unequal DAC and ADC rates, in which case @@ -489,6 +490,9 @@ au1xxx_dbdma_reset(db->dmanr); db->stopped = 1; + db->count = 0; + db->dma_qcount = 0; + db->nextIn = db->nextOut = db->rawbuf; spin_unlock_irqrestore(&s->lock, flags); } @@ -518,6 +522,9 @@ au1xxx_dbdma_reset(db->dmanr); db->stopped = 1; + db->count = 0; + db->dma_qcount = 0; + db->nextIn = db->nextOut = db->rawbuf; spin_unlock_irqrestore(&s->lock, flags); } @@ -609,7 +616,8 @@ spin_lock_irqsave(&s->lock, flags); - set_xmit_slots(db->num_channels); + au1xxx_dbdma_reset(db->dmanr); + au_writel(PSC_AC97PCR_TC, PSC_AC97PCR); au_sync(); au_writel(PSC_AC97PCR_TS, PSC_AC97PCR); @@ -634,17 +642,20 @@ spin_lock_irqsave(&s->lock, flags); + au1xxx_dbdma_reset(db->dmanr); + /* Put two buffers on the ring to get things started. */ - for (i=0; i<2; i++) { - au1xxx_dbdma_put_dest(db->dmanr, db->nextIn, db->dma_fragsize); + for (i=0; idmanr, db->nextIn, db->dma_fragsize) ) { - db->nextIn += db->dma_fragsize; - if (db->nextIn >= db->rawbuf + db->dmasize) - db->nextIn -= db->dmasize; + db->nextIn += db->dma_fragsize; + if (db->nextIn >= db->rawbuf + db->dmasize) + db->nextIn -= db->dmasize; + } else + info("Cannot put dest %i", i); } - set_recv_slots(db->num_channels); au1xxx_dbdma_start(db->dmanr); au_writel(PSC_AC97PCR_RC, PSC_AC97PCR); au_sync(); @@ -665,9 +676,12 @@ if (!db->rawbuf) { db->ready = db->mapped = 0; db->buforder = 5; /* 32 * PAGE_SIZE */ + bufs = PAGE_SIZE << db->buforder; db->rawbuf = kmalloc((PAGE_SIZE << db->buforder), GFP_KERNEL); if (!db->rawbuf) return -ENOMEM; + } else { + bufs = PAGE_SIZE << db->buforder; } db->cnt_factor = 1; @@ -686,7 +700,6 @@ 2 : db->num_channels); user_bytes_per_sec = rate * db->user_bytes_per_sample; - bufs = PAGE_SIZE << db->buforder; if (db->ossfragshift) { if ((1000 << db->ossfragshift) < user_bytes_per_sec) db->fragshift = ld2(user_bytes_per_sec/1000); @@ -731,6 +744,7 @@ static int prog_dmabuf_adc(struct au1550_state *s) { + dbg("prog_dmabuf_adc s%i c%i", s->dma_adc.sample_size, s->dma_adc.num_channels); stop_adc(s); return prog_dmabuf(s, &s->dma_adc); @@ -739,6 +753,8 @@ static int prog_dmabuf_dac(struct au1550_state *s) { + dbg("prog_dmabuf_dac s%i c%i", s->dma_dac.sample_size, s->dma_dac.num_channels); + stop_dac(s); return prog_dmabuf(s, &s->dma_dac); } @@ -752,20 +768,20 @@ { struct au1550_state *s = (struct au1550_state *) dev_id; struct dmabuf *db = &s->dma_dac; +#ifdef AU1000_VERBOSE_DEBUG u32 ac97c_stat; +#endif - ac97c_stat = au_readl(PSC_AC97STAT); #ifdef AU1000_VERBOSE_DEBUG - if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE)) - dbg("AC97C status = 0x%08x", ac97c_stat); +// if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE)) +// dbg("AC97C status = 0x%08x", ac97c_stat); #endif db->dma_qcount--; - if (db->count >= db->fragsize) { - if (au1xxx_dbdma_put_source(db->dmanr, db->nextOut, - db->fragsize) == 0) { - err("qcount < 2 and no ring room!"); - } + // put source buffers as long as we have data and free dma descr + while ( (db->count >= db->fragsize) && + (au1xxx_dbdma_put_source(db->dmanr, db->nextOut, + db->fragsize) ) ) { db->nextOut += db->fragsize; if (db->nextOut >= db->rawbuf + db->dmasize) db->nextOut -= db->dmasize; @@ -785,30 +799,44 @@ struct dmabuf *dp = &s->dma_adc; u32 obytes; char *obuf; +#ifdef AU1000_VERBOSE_DEBUG + u32 ac97c_stat; +#endif - /* Pull the buffer from the dma queue. - */ - au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes); - - if ((dp->count + obytes) > dp->dmasize) { - /* Overrun. Stop ADC and log the error - */ - stop_adc(s); - dp->error++; - err("adc overrun"); - return; - } +#ifdef AU1000_VERBOSE_DEBUG +// if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE)) +// dbg("AC97C status = 0x%08x", ac97c_stat); +#endif - /* Put a new empty buffer on the destination DMA. + /* Pull completed buffer(s) from the dma queue. */ - au1xxx_dbdma_put_dest(dp->dmanr, dp->nextIn, dp->dma_fragsize); + int cnt=0; + while ( au1xxx_dbdma_get_dest(dp->dmanr, (void *)(&obuf), &obytes) ) { + if ((dp->count + obytes) > dp->dmasize) { + /* Overrun. Stop ADC and log the error + */ + stop_adc(s); + dp->error++; + err("adc overrun"); + break; + } - dp->nextIn += dp->dma_fragsize; - if (dp->nextIn >= dp->rawbuf + dp->dmasize) - dp->nextIn -= dp->dmasize; + dp->count += obytes; + dp->total_bytes += obytes; - dp->count += obytes; - dp->total_bytes += obytes; + /* Put new empty buffer(s) on the destination DMA. + */ + while ( au1xxx_dbdma_put_dest(dp->dmanr, dp->nextIn, dp->dma_fragsize) ) { + dp->nextIn += dp->dma_fragsize; + if (dp->nextIn >= dp->rawbuf + dp->dmasize) + dp->nextIn -= dp->dmasize; + } + + if ( ++cnt>3 ) { + // get max 4 buffers at once here + break; + } + } /* wake up anybody listening */ @@ -1078,13 +1104,10 @@ /* wait for samples in ADC dma buffer */ do { - if (db->stopped) + if (db->stopped) start_adc(s); - spin_lock_irqsave(&s->lock, flags); + set_current_state(TASK_INTERRUPTIBLE); avail = db->count; - if (avail <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); if (avail <= 0) { if (file->f_flags & O_NONBLOCK) { if (!ret) @@ -1163,11 +1189,8 @@ /* wait for space in playback buffer */ do { - spin_lock_irqsave(&s->lock, flags); + set_current_state(TASK_INTERRUPTIBLE); avail = (int) db->dmasize - db->count; - if (avail <= 0) - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&s->lock, flags); if (avail <= 0) { if (file->f_flags & O_NONBLOCK) { if (!ret) @@ -1190,6 +1214,7 @@ if ((cnt = copy_dmabuf_user(db, (char *) buffer, count > avail ? avail : count, 0)) < 0) { + err("copy_dmabuf_user error %i", cnt); if (!ret) ret = -EFAULT; goto out; @@ -1213,6 +1228,7 @@ err("qcount < 2 and no ring room!"); } db->nextOut += db->fragsize; + db->count -= db->fragsize; if (db->nextOut >= db->rawbuf + db->dmasize) db->nextOut -= db->dmasize; db->total_bytes += db->dma_fragsize; @@ -1244,13 +1269,20 @@ unsigned int mask = 0; if (file->f_mode & FMODE_WRITE) { - if (!s->dma_dac.ready) + if (!s->dma_dac.ready) { + err("poll: dma_dac not ready"); return 0; + } poll_wait(file, &s->dma_dac.wait, wait); } if (file->f_mode & FMODE_READ) { - if (!s->dma_adc.ready) + if (!s->dma_adc.ready) { + err("poll: dma_adc not ready"); return 0; + } + if ( s->dma_adc.stopped ) { + start_adc(s); + } poll_wait(file, &s->dma_adc.wait, wait); } @@ -1388,7 +1420,7 @@ break; } if (count < sizeof(ioctl_str) / sizeof(ioctl_str[0])) - dbg("ioctl %s, arg=0x%lx", ioctl_str[count].str, arg); + dbg("ioctl %s(%x), arg=0x%lx", ioctl_str[count].str, cmd, arg); else dbg("ioctl 0x%x unknown, arg=0x%lx", cmd, arg); #endif @@ -1456,12 +1488,14 @@ if (file->f_mode & FMODE_READ) { stop_adc(s); s->dma_adc.num_channels = val ? 2 : 1; + set_recv_slots(s->dma_adc.num_channels); if ((ret = prog_dmabuf_adc(s))) return ret; } if (file->f_mode & FMODE_WRITE) { stop_dac(s); s->dma_dac.num_channels = val ? 2 : 1; + set_xmit_slots(s->dma_dac.num_channels); if (s->codec_ext_caps & AC97_EXT_DACS) { /* disable surround and center/lfe in AC'97 */ @@ -1486,6 +1520,7 @@ return -EINVAL; stop_adc(s); s->dma_adc.num_channels = val; + set_recv_slots(s->dma_adc.num_channels); if ((ret = prog_dmabuf_adc(s))) return ret; } @@ -1543,6 +1578,7 @@ } s->dma_dac.num_channels = val; + set_xmit_slots(s->dma_dac.num_channels); if ((ret = prog_dmabuf_dac(s))) return ret; } @@ -1799,6 +1835,7 @@ return -EINVAL; } + info("mixdev_ioctl(%i)", cmd); return mixdev_ioctl(s->codec, cmd, arg); } @@ -1813,9 +1850,9 @@ #ifdef AU1000_VERBOSE_DEBUG if (file->f_flags & O_NONBLOCK) - dbg(__FUNCTION__ ": non-blocking"); + info("%s : non-blocking", __FUNCTION__); else - dbg(__FUNCTION__ ": blocking"); + info("%s : blocking", __FUNCTION__); #endif file->private_data = s; @@ -1846,6 +1883,7 @@ s->dma_adc.num_channels = 1; s->dma_adc.sample_size = 8; set_adc_rate(s, 8000); + set_recv_slots(s->dma_adc.num_channels); if ((minor & 0xf) == SND_DEV_DSP16) s->dma_adc.sample_size = 16; } @@ -1856,22 +1894,31 @@ s->dma_dac.num_channels = 1; s->dma_dac.sample_size = 8; set_dac_rate(s, 8000); + set_xmit_slots(s->dma_dac.num_channels); if ((minor & 0xf) == SND_DEV_DSP16) s->dma_dac.sample_size = 16; } if (file->f_mode & FMODE_READ) { - if ((ret = prog_dmabuf_adc(s))) + if ((ret = prog_dmabuf_adc(s))) { + err("prog_dmabuf_adc failed"); + up(&s->open_sem); return ret; + } + } if (file->f_mode & FMODE_WRITE) { - if ((ret = prog_dmabuf_dac(s))) + if ((ret = prog_dmabuf_dac(s))) { + err("prog_dmabuf_dac failed"); + up(&s->open_sem); return ret; + } } s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); up(&s->open_sem); init_MUTEX(&s->sem); + return 0; } @@ -1954,12 +2001,13 @@ err("AC'97 ports in use"); } + /* Allocate the DMA Channels */ if ((s->dma_dac.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_MEM_CHAN, DBDMA_AC97_TX_CHAN, dac_dma_interrupt, (void *)s)) == 0) { err("Can't get DAC DMA"); - goto err_dma1; + goto err_dev1; } au1xxx_dbdma_set_devwidth(s->dma_dac.dmanr, 16); if (au1xxx_dbdma_ring_alloc(s->dma_dac.dmanr, @@ -1968,10 +2016,11 @@ goto err_dma1; } + if ((s->dma_adc.dmanr = au1xxx_dbdma_chan_alloc(DBDMA_AC97_RX_CHAN, - DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) { + DBDMA_MEM_CHAN, adc_dma_interrupt, (void *)s)) == 0) { err("Can't get ADC DMA"); - goto err_dma2; + goto err_dma1; } au1xxx_dbdma_set_devwidth(s->dma_adc.dmanr, 16); if (au1xxx_dbdma_ring_alloc(s->dma_adc.dmanr, @@ -1980,7 +2029,7 @@ #ifdef AU1550_DEBUG /* intialize the debug proc device */ - s->ps = create_proc_read_entry(AU1000_MODULE_NAME, 0, NULL, + s->ps = create_proc_read_entry(AU1550_MODULE_NAME, 0, NULL, proc_au1550_dump, NULL); #endif /* AU1550_DEBUG */ @@ -2102,11 +2150,11 @@ unregister_sound_mixer(s->codec->dev_mixer); err_dev2: unregister_sound_dsp(s->dev_audio); - err_dev1: - au1xxx_dbdma_chan_free(s->dma_adc.dmanr); err_dma2: - au1xxx_dbdma_chan_free(s->dma_dac.dmanr); + au1xxx_dbdma_chan_free(s->dma_adc.dmanr); err_dma1: + au1xxx_dbdma_chan_free(s->dma_dac.dmanr); + err_dev1: release_region(PHYSADDR(AC97_PSC_SEL), 0x30); ac97_release_codec(s->codec); @@ -2125,11 +2173,11 @@ remove_proc_entry(AU1000_MODULE_NAME, NULL); #endif /* AU1000_DEBUG */ synchronize_irq(); + unregister_sound_dsp(s->dev_audio); + unregister_sound_mixer(s->codec->dev_mixer); au1xxx_dbdma_chan_free(s->dma_adc.dmanr); au1xxx_dbdma_chan_free(s->dma_dac.dmanr); release_region(PHYSADDR(AC97_PSC_SEL), 0x30); - unregister_sound_dsp(s->dev_audio); - unregister_sound_mixer(s->codec->dev_mixer); ac97_release_codec(s->codec); }