void au1xxx_ddma_del_device(u32 devid) { dbdev_tab_t *p = find_dbdev_id(devid); if (p != NULL) { memset(p, 0, sizeof(dbdev_tab_t)); p->dev_id = ~0; } }
u32 au1xxx_ddma_add_device(dbdev_tab_t *dev) { u32 ret = 0; dbdev_tab_t *p; 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(KERN_DEBUG "add_device: id:%x flags:%x padd:%x\n", p->dev_id, p->dev_flags, p->dev_physaddr); #endif } return ret; }
/* Allocate a channel and return a non-zero descriptor if successful. */ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, void (*callback)(int, void *), void *callparam) { unsigned long flags; u32 used, chan; u32 dcp; int i; dbdev_tab_t *stp, *dtp; chan_tab_t *ctp; au1x_dma_chan_t *cp; /* * We do the initialization on the first channel allocation. * We have to wait because of the interrupt handler initialization * which can't be done successfully during board set up. */ if (!dbdma_initialized) return 0; stp = find_dbdev_id(srcid); if (stp == NULL) return 0; dtp = find_dbdev_id(destid); if (dtp == NULL) return 0; used = 0; /* Check to see if we can get both channels. */ spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); if (!(stp->dev_flags & DEV_FLAGS_INUSE) || (stp->dev_flags & DEV_FLAGS_ANYUSE)) { /* Got source */ stp->dev_flags |= DEV_FLAGS_INUSE; if (!(dtp->dev_flags & DEV_FLAGS_INUSE) || (dtp->dev_flags & DEV_FLAGS_ANYUSE)) { /* Got destination */ dtp->dev_flags |= DEV_FLAGS_INUSE; } else { /* Can't get dest. Release src. */ stp->dev_flags &= ~DEV_FLAGS_INUSE; used++; } } else used++; spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags); if (used) return 0; /* Let's see if we can allocate a channel for it. */ ctp = NULL; chan = 0; spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); for (i = 0; i < NUM_DBDMA_CHANS; i++) if (chan_tab_ptr[i] == NULL) { /* * If kmalloc fails, it is caught below same * as a channel not available. */ ctp = kmalloc(sizeof(chan_tab_t), GFP_ATOMIC); chan_tab_ptr[i] = ctp; break; } spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags); if (ctp != NULL) { memset(ctp, 0, sizeof(chan_tab_t)); ctp->chan_index = chan = i; dcp = KSEG1ADDR(AU1550_DBDMA_PHYS_ADDR); dcp += (0x0100 * chan); ctp->chan_ptr = (au1x_dma_chan_t *)dcp; cp = (au1x_dma_chan_t *)dcp; ctp->chan_src = stp; ctp->chan_dest = dtp; ctp->chan_callback = callback; ctp->chan_callparam = callparam; /* Initialize channel configuration. */ i = 0; if (stp->dev_intlevel) i |= DDMA_CFG_SED; if (stp->dev_intpolarity) i |= DDMA_CFG_SP; if (dtp->dev_intlevel) 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; wmb(); /* drain writebuffer */ /* * Return a non-zero value that can be used to find the channel * information in subsequent operations. */ return (u32)(&chan_tab_ptr[chan]); } /* Release devices */ stp->dev_flags &= ~DEV_FLAGS_INUSE; dtp->dev_flags &= ~DEV_FLAGS_INUSE; return 0; }
/* Allocate a channel and return a non-zero descriptor if successful. */ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid, void (*callback)(int, void *, struct pt_regs *), void *callparam) { unsigned long flags; u32 used, chan, rv; u32 dcp; int i; dbdev_tab_t *stp, *dtp; chan_tab_t *ctp; volatile au1x_dma_chan_t *cp; /* We do the intialization on the first channel allocation. * We have to wait because of the interrupt handler initialization * which can't be done successfully during board set up. */ if (!dbdma_initialized) 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; used = 0; rv = 0; /* Check to see if we can get both channels. */ spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); if (!(stp->dev_flags & DEV_FLAGS_INUSE) || (stp->dev_flags & DEV_FLAGS_ANYUSE)) { /* Got source */ stp->dev_flags |= DEV_FLAGS_INUSE; if (!(dtp->dev_flags & DEV_FLAGS_INUSE) || (dtp->dev_flags & DEV_FLAGS_ANYUSE)) { /* Got destination */ dtp->dev_flags |= DEV_FLAGS_INUSE; } else { /* Can't get dest. Release src. */ stp->dev_flags &= ~DEV_FLAGS_INUSE; used++; } } else { used++; } spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags); if (!used) { /* Let's see if we can allocate a channel for it. */ ctp = NULL; chan = 0; spin_lock_irqsave(&au1xxx_dbdma_spin_lock, flags); for (i=0; i<NUM_DBDMA_CHANS; i++) { if (chan_tab_ptr[i] == NULL) { /* If kmalloc fails, it is caught below same * as a channel not available. */ ctp = (chan_tab_t *)kmalloc(sizeof(chan_tab_t), GFP_KERNEL); chan_tab_ptr[i] = ctp; ctp->chan_index = chan = i; break; } } spin_unlock_irqrestore(&au1xxx_dbdma_spin_lock, flags); if (ctp != NULL) { memset(ctp, 0, sizeof(chan_tab_t)); dcp = DDMA_CHANNEL_BASE; dcp += (0x0100 * chan); ctp->chan_ptr = (au1x_dma_chan_t *)dcp; cp = (volatile au1x_dma_chan_t *)dcp; ctp->chan_src = stp; ctp->chan_dest = dtp; ctp->chan_callback = callback; ctp->chan_callparam = callparam; /* Initialize channel configuration. */ i = 0; if (stp->dev_intlevel) i |= DDMA_CFG_SED; if (stp->dev_intpolarity) i |= DDMA_CFG_SP; if (dtp->dev_intlevel) i |= DDMA_CFG_DED; if (dtp->dev_intpolarity) i |= DDMA_CFG_DP; cp->ddma_cfg = i; au_sync(); /* Return a non-zero value that can be used to * find the channel information in subsequent * operations. */ rv = (u32)(&chan_tab_ptr[chan]); } else { /* Release devices. */ stp->dev_flags &= ~DEV_FLAGS_INUSE; dtp->dev_flags &= ~DEV_FLAGS_INUSE; } } return rv; }