!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/arch/arm/mach-sa1100/   drwxr-xr-x
Free 318.34 GB of 458.09 GB (69.49%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     dma-sa1111.c (9.09 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 *  linux/arch/arm/mach-sa1100/dma-sa1111.c
 *
 *  Copyright (C) 2000 John Dorsey
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  4 September 2000 - created.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/errno.h>

#include <asm/system.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/dma.h>

// #define DEBUG
#ifdef DEBUG
#define DPRINTK( s, arg... )  printk( "dma<%s>: " s, dma->device_id , ##arg )
#else
#define DPRINTK( x... )
#endif


/*
 * Control register structure for the SA1111 SAC DMA
 */

typedef struct {
    volatile u_long SAD_CS;
    volatile dma_addr_t SAD_SA;
    volatile u_long SAD_CA;
    volatile dma_addr_t SAD_SB;
    volatile u_long SAD_CB;
} dma_regs_t;

#include "dma.h"


void sa1111_reset_sac_dma(dmach_t channel)
{
    sa1100_dma_t *dma = &dma_chan[channel];
    dma->regs->SAD_CS = 0;
    mdelay(1);
    dma->dma_a = dma->dma_b = 0;
}


int start_sa1111_sac_dma(sa1100_dma_t *dma, dma_addr_t dma_ptr, size_t size)
{
      dma_regs_t *sac_regs = dma->regs;

    DPRINTK(" SAC DMA %cCS %02x at %08x (%d)\n",
        (sac_regs==&SADTCS)?'T':'R', sac_regs->SAD_CS, dma_ptr, size);

    /* The minimum transfer length requirement has not yet been
     * verified:
     */
    if( size < SA1111_SAC_DMA_MIN_XFER )
      printk(KERN_WARNING "Warning: SAC xfers below %u bytes may be buggy!"
         " (%u bytes)\n", SA1111_SAC_DMA_MIN_XFER, size);

    if( dma->dma_a && dma->dma_b ){
          DPRINTK("  neither engine available! (A %d, B %d)\n",
            dma->dma_a, dma->dma_b);
          return -1;
    }

    if( sa1111_check_dma_bug(dma_ptr) )
          printk(KERN_WARNING "Warning: DMA address %08x is buggy!\n",
               dma_ptr);

    if( (dma->last_dma || dma->dma_b) && dma->dma_a == 0 ){
          if( sac_regs->SAD_CS & SAD_CS_DBDB ){
              DPRINTK("  awaiting \"done B\" interrupt, not starting\n");
            return -1;
        }
        sac_regs->SAD_SA = SA1111_DMA_ADDR((u_int)dma_ptr);
        sac_regs->SAD_CA = size;
        sac_regs->SAD_CS = SAD_CS_DSTA | SAD_CS_DEN;
        ++dma->dma_a;
        DPRINTK("  with A [%02lx %08lx %04lx]\n", sac_regs->SAD_CS,
            sac_regs->SAD_SA, sac_regs->SAD_CA);
    } else {
          if( sac_regs->SAD_CS & SAD_CS_DBDA ){
              DPRINTK("  awaiting \"done A\" interrupt, not starting\n");
            return -1;
        }
        sac_regs->SAD_SB = SA1111_DMA_ADDR((u_int)dma_ptr);
        sac_regs->SAD_CB = size;
        sac_regs->SAD_CS = SAD_CS_DSTB | SAD_CS_DEN;
        ++dma->dma_b;
        DPRINTK("  with B [%02lx %08lx %04lx]\n", sac_regs->SAD_CS,
            sac_regs->SAD_SB, sac_regs->SAD_CB);
    }

    /* Additional delay to avoid DMA engine lockup during record: */
    if( sac_regs == (dma_regs_t*)&SADRCS )
          mdelay(1);    /* NP : wouuuh! ugly... */

    return 0;
}


static void sa1111_sac_dma_irq(int irq, void *dev_id, struct pt_regs *regs)
{
      sa1100_dma_t *dma = (sa1100_dma_t *) dev_id;

    DPRINTK("irq %d, last DMA serviced was %c, CS %02x\n", irq,
        dma->last_dma?'B':'A', dma->regs->SAD_CS);

    /* Occasionally, one of the DMA engines (A or B) will
     * lock up. We try to deal with this by quietly kicking
     * the control register for the afflicted transfer
     * direction.
     *
     * Note for the debugging-inclined: we currently aren't
     * properly flushing the DMA engines during channel
     * shutdown. A slight hiccup at the beginning of playback
     * after a channel has been stopped can be heard as
     * evidence of this. Programmatically, this shows up
     * as either a locked engine, or a spurious interrupt. -jd
     */

    if(irq==AUDXMTDMADONEA || irq==AUDRCVDMADONEA){

          if(dma->last_dma == 0){
              DPRINTK("DMA B has locked up!\n");
            dma->regs->SAD_CS = 0;
            mdelay(1);
            dma->dma_a = dma->dma_b = 0;
        } else {
              if(dma->dma_a == 0)
                  DPRINTK("spurious SAC IRQ %d\n", irq);
            else {
                  --dma->dma_a;

                /* Servicing the SAC DMA engines too quickly
                 * after they issue a DONE interrupt causes
                 * them to lock up.
                 */
                if(irq==AUDRCVDMADONEA || irq==AUDRCVDMADONEB)
                      mdelay(1);
            }
        }

        dma->regs->SAD_CS = SAD_CS_DBDA | SAD_CS_DEN; /* w1c */
        dma->last_dma = 0;

    } else {

          if(dma->last_dma == 1){
              DPRINTK("DMA A has locked up!\n");
            dma->regs->SAD_CS = 0;
            mdelay(1);
            dma->dma_a = dma->dma_b = 0;
        } else {
              if(dma->dma_b == 0)
                  DPRINTK("spurious SAC IRQ %d\n", irq);
            else {
                  --dma->dma_b;

                /* See lock-up note above. */
                if(irq==AUDRCVDMADONEA || irq==AUDRCVDMADONEB)
                      mdelay(1);
            }
        }

        dma->regs->SAD_CS = SAD_CS_DBDB | SAD_CS_DEN; /* w1c */
        dma->last_dma = 1;

    }

    /* NP: maybe this shouldn't be called in all cases? */
    sa1100_dma_done (dma);
}


int sa1111_sac_request_dma(dmach_t *channel, const char *device_id,
               unsigned int direction)
{
    sa1100_dma_t *dma = NULL;
    int ch, irq, err;

    *channel = -1;        /* to be sure we catch the freeing of a misregistered channel */

    ch = SA1111_SAC_DMA_BASE + direction;

    if (!channel_is_sa1111_sac(ch)) {
          printk(KERN_ERR "%s: invalid SA-1111 SAC DMA channel (%d)\n",
               device_id, ch);
        return -1;
    }

    dma = &dma_chan[ch];

    if (xchg(&dma->in_use, 1) == 1) {
          printk(KERN_ERR "%s: SA-1111 SAC DMA channel %d in use\n",
               device_id, ch);
        return -EBUSY;
    }

    irq = AUDXMTDMADONEA + direction;
    err = request_irq(irq, sa1111_sac_dma_irq, SA_INTERRUPT,
              device_id, (void *) dma);
    if (err) {
        printk(KERN_ERR
               "%s: unable to request IRQ %d for DMA channel %d (A)\n",
               device_id, irq, ch);
        dma->in_use = 0;
        return err;
    }

    irq = AUDXMTDMADONEB + direction;
    err = request_irq(irq, sa1111_sac_dma_irq, SA_INTERRUPT,
              device_id, (void *) dma);
    if (err) {
        printk(KERN_ERR
               "%s: unable to request IRQ %d for DMA channel %d (B)\n",
               device_id, irq, ch);
        dma->in_use = 0;
        return err;
    }

    *channel = ch;
    dma->device_id = device_id;
    dma->callback = NULL;
    dma->spin_size = 0;

    return 0;
}


/* FIXME:  need to complete the three following functions */

int sa1111_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr)
{
    sa1100_dma_t *dma = &dma_chan[channel];
    int flags, ret;

    local_irq_save(flags);
    if (dma->curr && dma->spin_ref <= 0) {
        dma_buf_t *buf = dma->curr;
        if (buf_id)
            *buf_id = buf->id;
        /* not fully accurate but still... */
        *addr = buf->dma_ptr;
        ret = 0;
    } else {
        if (buf_id)
            *buf_id = NULL;
        *addr = 0;
        ret = -ENXIO;
    }
    local_irq_restore(flags);
    return ret;
}

int sa1111_dma_stop(dmach_t channel)
{
    return 0;
}

int sa1111_dma_resume(dmach_t channel)
{
    return 0;
}


void sa1111_cleanup_sac_dma(dmach_t channel)
{
    sa1100_dma_t *dma = &dma_chan[channel];
    free_irq(AUDXMTDMADONEA + (channel - SA1111_SAC_DMA_BASE), (void*) dma);
    free_irq(AUDXMTDMADONEB + (channel - SA1111_SAC_DMA_BASE), (void*) dma);
}


/* According to the "Intel StrongARM SA-1111 Microprocessor Companion
 * Chip Specification Update" (June 2000), erratum #7, there is a
 * significant bug in Serial Audio Controller DMA. If the SAC is
 * accessing a region of memory above 1MB relative to the bank base,
 * it is important that address bit 10 _NOT_ be asserted. Depending
 * on the configuration of the RAM, bit 10 may correspond to one
 * of several different (processor-relative) address bits.
 *
 * This routine only identifies whether or not a given DMA address
 * is susceptible to the bug.
 */
int sa1111_check_dma_bug(dma_addr_t addr){
    unsigned int physaddr=SA1111_DMA_ADDR((unsigned int)addr);

    /* Section 4.6 of the "Intel StrongARM SA-1111 Development Module
     * User's Guide" mentions that jumpers R51 and R52 control the
     * target of SA-1111 DMA (either SDRAM bank 0 on Assabet, or
     * SDRAM bank 1 on Neponset). The default configuration selects
     * Assabet, so any address in bank 1 is necessarily invalid.
     */
    if((machine_is_assabet() || machine_is_pfs168()) && addr >= 0xc8000000)
          return -1;

    /* The bug only applies to buffers located more than one megabyte
     * above the start of the target bank:
     */
    if(physaddr<(1<<20))
          return 0;

    switch(FExtr(SBI_SMCR, SMCR_DRAC)){
    case 01: /* 10 row + bank address bits, A<20> must not be set */
          if(physaddr & (1<<20))
              return -1;
        break;
    case 02: /* 11 row + bank address bits, A<23> must not be set */
          if(physaddr & (1<<23))
              return -1;
        break;
    case 03: /* 12 row + bank address bits, A<24> must not be set */
          if(physaddr & (1<<24))
              return -1;
        break;
    case 04: /* 13 row + bank address bits, A<25> must not be set */
          if(physaddr & (1<<25))
              return -1;
        break;
    case 05: /* 14 row + bank address bits, A<20> must not be set */
          if(physaddr & (1<<20))
              return -1;
        break;
    case 06: /* 15 row + bank address bits, A<20> must not be set */
          if(physaddr & (1<<20))
              return -1;
        break;
    default:
          printk(KERN_ERR "%s(): invalid SMCR DRAC value 0%lo\n",
               __FUNCTION__, FExtr(SBI_SMCR, SMCR_DRAC));
        return -1;
    }

    return 0;
}


EXPORT_SYMBOL(sa1111_sac_request_dma);
EXPORT_SYMBOL(sa1111_check_dma_bug);


static int __init sa1111_init_sac_dma(void)
{
    int channel = SA1111_SAC_DMA_BASE;
    dma_chan[channel++].regs = (dma_regs_t *) &SADTCS;
    dma_chan[channel++].regs = (dma_regs_t *) &SADRCS;
    return 0;
}

__initcall(sa1111_init_sac_dma);

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0248 ]--