• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天下

            記錄修行的印記

            s3c2410的dma操作的一般步驟

            s3c2410的dma操作的一般步驟

            一般的,在s3c2440中,要想進(jìn)行dma傳輸,需要一下七個(gè)步驟:

            一:
            /* s3c2410_request_dma
             *
             * get control of an dma channel
            */
            int s3c2410_dma_request(unsigned int channel,
                                    
            struct s3c2410_dma_client *client,
                                    
            void *dev)
                
            s3c2410_dma_client的定義為:
            struct s3c2410_dma_client {
                
            char    *name;
            };

            二:
            /* DMA configuration for each channel
             *
             * DISRCC -> source of the DMA (AHB(系統(tǒng)總線),APB(外圍總線))
             * DISRC  -> source address of the DMA
             * DIDSTC -> destination of the DMA (AHB,APD)
             * DIDST  -> destination address of the DMA
            */
            /* s3c2410_dma_config
             *
             * xfersize:     size of unit in bytes (1,2,4)
             * dcon:         base value of the DCONx register
            */

            int s3c2410_dma_config(dmach_t channel,
                                   
            int xferunit,
                                   
            int dcon)
            根據(jù)xferunit以及dcon設(shè)置通道的控制寄存器DCONx
            xferunit為每次傳輸?shù)臄?shù)據(jù)大小:
            0:byte 1:half word 2:word

            每個(gè) DMA 通道都有 
            9 個(gè)控制寄存器(4 個(gè)通道 DMA 控制器共計(jì) 36 個(gè)寄存器)。
            6 個(gè)寄存器用來(lái)控制 DMA 傳輸,其他三個(gè)監(jiān)視 DMA 控制器的狀態(tài)。這些寄存器的詳細(xì)情況如下:
            1)DMA 初始源寄存器(DISRC)
            2)DMA初始源控制寄存器(DISRCC)
            3)DMA初始目的寄存器(DIDST)
            4)DMA初始目的控制寄存器(DIDSTC)
            5)DMA控制寄存器(DCON)
            6)DMA狀態(tài)寄存器(DSTAT)
            7)DMA當(dāng)前源寄存器(DCSRC)
            8)DMA當(dāng)前目的寄存器(DCDST)
            9)DMA屏蔽觸發(fā)寄存器(DMASKTRIG)

            三:
            int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
            {
                
            struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
                
            if (chan == NULL)
                    
            return -EINVAL;
                pr_debug(
            "%s: chan=%p, callback rtn=%p\n", __func__, chan, rtn);
                chan
            ->callback_fn = rtn;
                
            return 0;
            }    
            設(shè)置相應(yīng)的dma通道完成一次dma傳輸后的回調(diào)函數(shù),也即是s3c2410_dma_enqueue完成后會(huì)調(diào)用的函數(shù)

            回調(diào)函數(shù)應(yīng)具有一下格式:
            /* s3c2410_dma_cbfn_t
             *
             * buffer callback routine type
            */
            typedef 
            void (*s3c2410_dma_cbfn_t)(struct s3c2410_dma_chan *,
                                               
            void *buf, int size,
                                               
            enum s3c2410_dma_buffresult result);

            buf可以傳遞一些有用的數(shù)據(jù),在uda1314的驅(qū)動(dòng)中,傳遞的是audio_buf_t結(jié)構(gòu)體


            四:
            int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
            {
                
            struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
                
            if (chan == NULL)
                    
            return -EINVAL;
                pr_debug(
            "%s: chan=%p, flags=%08x\n", __func__, chan, flags);
                chan
            ->flags = flags;
                
            return 0;
            }

            五:
            /* s3c2410_dma_devconfig
             *
             * configure the dma source/destination hardware type and address
             *
             * source:    S3C2410_DMASRC_HW: source is hardware
             *            S3C2410_DMASRC_MEM: source is memory
             *
             * hwcfg:     the value for xxxSTCn register,
             *            bit 0: 0=increment pointer, 1=leave pointer
             *            bit 1: 0=source is AHB, 1=source is APB
             *
             * devaddr:   physical address of the source
            */

            int s3c2410_dma_devconfig(int channel,
                                      
            enum s3c2410_dmasrc source,
                                      
            int hwcfg,
                                      unsigned 
            long devaddr)
                
            六:
            /*
             * Allocate memory for a coherent(連續(xù)的) mapping.
             
            */
            void *dma_alloc_coherent(struct device *dev,size_t size,dma_addr_t *dma_handle,int flag)
            如:        
            void *pLogicAddr = NULL;/*邏輯地址*/
            dma_addr_t pBusAddr 
            = NULL;/*總線地址(實(shí)際物理地址)*/
            pLogicAddr 
            = dma_alloc_coherent(NULL, 480*640&pBusAddr, GFP_KERNEL | GFP_DMA);
                    
            該函數(shù)實(shí)際獲得兩個(gè)地址,
            1、函數(shù)的返回值是一個(gè)void *,代表緩沖區(qū)的內(nèi)核虛擬地址
            2、相關(guān)的總線地址,保存在dma_handle中
                
            dma關(guān)心的是總線地址。
            物理地址與總線地址
            1) 物理地址是與CPU相關(guān)的。在CPU的地址信號(hào)線上產(chǎn)生的就是物理地址。在程序指令中的虛擬地址經(jīng)過(guò)段映射和頁(yè)面映射后,就生成了物理地址,這個(gè)物理地址被放到CPU的地址線上。
            2) 總線地址,顧名思義,是與總線相關(guān)的,就是總線的地址線或在地址周期上產(chǎn)生的信號(hào)。外設(shè)使用的是總線地址。
            3) 物理地址與總線地址之間的關(guān)系由系統(tǒng)的設(shè)計(jì)決定的。在x86平臺(tái)上,物理地址與PCI總線地址是相同的。在其他平臺(tái)上,也許會(huì)有某種轉(zhuǎn)換,通常是線性的轉(zhuǎn)換。    


            七:
            /* s3c2410_dma_enqueue
             *
             * queue an given buffer for dma transfer.
             *
             * id         the device driver's id information for this buffer
             * data       the physical address of the buffer data
             * size       the size of the buffer in bytes
             *
             * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
             * is checked, and if set, the channel is started. If this flag isn't set,
             * then an error will be returned.
             *
             * It is possible to queue more than one DMA buffer onto a channel at
             * once, and the code will deal with the re-loading of the next buffer
             * when necessary.
            */

            int s3c2410_dma_enqueue(unsigned int channel, void *id,dma_addr_t data, int size)
            將dma_alloc_coherent中得到的dmaphys傳遞給s3c2410_dma_enqueue. 
            s3c2410_dma_enqueue提交一次dma請(qǐng)求,當(dāng)dma通道可用的時(shí)候通過(guò)s3c2410_dma_loadbuffer開(kāi)始一次傳輸,傳輸完成后會(huì)產(chǎn)生irq中斷。其dma的中斷服務(wù)函數(shù)中會(huì)繼續(xù)啟動(dòng)dma請(qǐng)求隊(duì)列中的請(qǐng)求,傳輸剩下的數(shù)據(jù)。

            /* s3c2410_dma_buffdone
             *
             * small wrapper to check if callback routine needs to be called, and
             * if so, call it
            */
            static inline void s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
                                                     
            enum s3c2410_dma_buffresult result)
            {
                
            if (chan->callback_fn != NULL) {
                    (chan
            ->callback_fn)(chan, buf->id, buf->size, result);
                }
            }    
            其中 s3c2410_dma_irq 會(huì)調(diào)用 s3c2410_dma_buffdone;
            static irqreturn_t s3c2410_dma_irq(int irq, void *devpw)
                
            /* s3c2410_request_dma
             *
             * get control of an dma channel
            */
            int s3c2410_dma_request(unsigned int channel,
                                    
            struct s3c2410_dma_client *client,
                                    
            void *dev)
            {
                
            struct s3c2410_dma_chan *chan;
                unsigned 
            long flags;
                
            int err;

                pr_debug(
            "dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
                     channel, client
            ->name, dev);

                local_irq_save(flags);
                chan 
            = s3c2410_dma_map_channel(channel);
                
            if (chan == NULL) {
                    local_irq_restore(flags);
                    
            return -EBUSY;
                }
                dbg_showchan(chan);
                chan
            ->client = client;
                chan
            ->in_use = 1;
                
            if (!chan->irq_claimed) {
                    pr_debug(
            "dma%d: %s : requesting irq %d\n",
                         channel, __func__, chan
            ->irq);

                    chan
            ->irq_claimed = 1;
                    local_irq_restore(flags);
                    err 
            = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
                              client
            ->name, (void *)chan);
                    local_irq_save(flags);
                    
            if (err) {
                        chan
            ->in_use = 0;
                        chan
            ->irq_claimed = 0;
                        local_irq_restore(flags);
                        printk(KERN_ERR 
            "%s: cannot get IRQ %d for DMA %d\n",
                               client
            ->name, chan->irq, chan->number);
                        
            return err;
                    }
                    chan
            ->irq_enabled = 1;
                }
                local_irq_restore(flags);
                
            /* need to setup */
                pr_debug(
            "%s: channel initialised, %p\n", __func__, chan);
                
            return chan->number | DMACH_LOW_LEVEL;
            }    


            /**
             *    request_irq - allocate an interrupt line
             *    @irq: Interrupt line to allocate
             *    @handler: Function to be called when the IRQ occurs
             *    @irqflags: Interrupt type flags
             *    @devname: An ascii name for the claiming device
             *    @dev_id: A cookie passed back to the handler function
             *
             *    This call allocates interrupt resources and enables the
             *    interrupt line and IRQ handling. From the point this
             *    call is made your handler function may be invoked. Since
             *    your handler function must clear any interrupt the board
             *    raises, you must take care both to initialise your hardware
             *    and to set up the interrupt handler in the right order.
             *
             *    Dev_id must be globally unique. Normally the address of the
             *    device data structure is used as the cookie. Since the handler
             *    receives this value it makes sense to use it.
             *
             *    If your interrupt is shared you must pass a non NULL dev_id
             *    as this is required when freeing the interrupt.
             *
             *    Flags:
             *
             *    IRQF_SHARED        Interrupt is shared
             *    IRQF_DISABLED    Disable local interrupts while processing
             *    IRQF_SAMPLE_RANDOM    The interrupt can be used for entropy
             *
             
            */
            int request_irq(unsigned int irq, irq_handler_t handler,
                    unsigned 
            long irqflags, const char *devname, void *dev_id)
            {
                
            struct irqaction *action;
                
            int retval;
                action 
            = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
                
            if (!action)
                    
            return -ENOMEM;
                action
            ->handler = handler;
                action
            ->flags = irqflags;
                cpus_clear(action
            ->mask);
                action
            ->name = devname;
                action
            ->next = NULL;
                action
            ->dev_id = dev_id;

                select_smp_affinity(irq);

                retval 
            = setup_irq(irq, action);
                
            if (retval)
                    kfree(action);

                
            return retval;
            }    


            /* s3c2410_dma_loadbuffer
             *
             * load a buffer, and update the channel state
            */
            static inline int s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
                                                        
            struct s3c2410_dma_buf *buf)
            {
                unsigned 
            long reload;
                pr_debug(
            "s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
                     buf, (unsigned 
            long)buf->data, buf->size);
                
            if (buf == NULL) {
                    dmawarn(
            "buffer is NULL\n");
                    
            return -EINVAL;
                }
                
            /* check the state of the channel before we do anything */
                
            if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
                    dmawarn(
            "load_state is S3C2410_DMALOAD_1LOADED\n");
                }
                
            if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
                    dmawarn(
            "state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
                }
                
            /* it would seem sensible if we are the last buffer to not bother
                 * with the auto-reload bit, so that the DMA engine will not try
                 * and load another transfer after this one has finished
                 
            */
                
            if (chan->load_state == S3C2410_DMALOAD_NONE) {
                    pr_debug(
            "load_state is none, checking for noreload (next=%p)\n",
                         buf
            ->next);
                    reload 
            = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
                } 
            else {
                    
            //pr_debug("load_state is %d => autoreload\n", chan->load_state);
                    reload = S3C2410_DCON_AUTORELOAD;
                }

                
            if ((buf->data & 0xf0000000!= 0x30000000) {
                    dmawarn(
            "dmaload: buffer is %p\n", (void *)buf->data);
                }

                writel(buf
            ->data, chan->addr_reg);

                dma_wrreg(chan, S3C2410_DMA_DCON,
                      chan
            ->dcon | reload | (buf->size/chan->xfer_unit));

                chan
            ->next = buf->next;

                
            /* update the state of the channel */

                
            switch (chan->load_state) {
                
            case S3C2410_DMALOAD_NONE:
                    chan
            ->load_state = S3C2410_DMALOAD_1LOADED;
                    
            break;

                
            case S3C2410_DMALOAD_1RUNNING:
                    chan
            ->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
                    
            break;

                
            default:
                    dmawarn(
            "dmaload: unknown state %d in loadbuffer\n",
                        chan
            ->load_state);
                    
            break;
                }
                
            return 0;
            }
             
            ============================================
            一些相關(guān)函數(shù)的說(shuō)明。供自己日后參考。
            --------------------------------------------------------------------------------------
            int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
            初始化全局變量dma_sel結(jié)構(gòu),在此函數(shù)中大家可能疑惑的是
                nmap 
            = kmalloc(map_sz, GFP_KERNEL);
                
            if (nmap == NULL)
                    
            return -ENOMEM;

                memcpy(nmap, sel
            ->map, map_sz);
                memcpy(
            &dma_sel, sel, sizeof(*sel));

                dma_sel.map 
            = nmap;
            這幾條語(yǔ)句,為什么用memcpy初始化為了dma_sel,而又要用再分配的nmap結(jié)構(gòu)去給dma_sel賦值。其答案是為了保險(xiǎn),因?yàn)閐ma_sel 中的map成員是個(gè)指針。對(duì)指針的操作是要很小心的。這里在此函數(shù)中重新定義一個(gè)指針變量,并指向它,就是為了防止別處定義的指針被撤消而造成越界訪問(wèn)。其實(shí)我認(rèn)為這沒(méi)有必要的。

            dma_sel的定義為struct s3c24xx_dma_selection dma_sel;
            而struct s3c24xx_dma_selection的定義為
            struct s3c24xx_dma_selection {
                
            struct s3c24xx_dma_map    *map;
                unsigned 
            long         map_size;
                unsigned 
            long         dcon_mask;

                
            void    (*select)(struct s3c2410_dma_chan *chan,
                          
            struct s3c24xx_dma_map *map);
            };


            --------------------------------------------------------------------------------------------------------
            struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
            此函數(shù)功能是: turn the 
            virtual channel number into a real, and un-used hardware channel.完成DMA通道的虛實(shí)映射
            在s3c2440_dma_mappings數(shù)組中查找相應(yīng)channel對(duì)應(yīng)的通道(
            0--4,有效未使用),并將映射關(guān)系記入dma_chan_map[channel]數(shù)組中。


            ---------------------------------------------------------------------------------------------------------
            static int __init s3c2410_init_dma(void)
            用于初始化s3c2410_dma_chan結(jié)構(gòu),并完成地址映射。

            -----------------------------------------------------------------------------------------------------------
            static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
            DMA通道虛實(shí)轉(zhuǎn)換

            -----------------------------------------------------------------------------------------------------------
            int s3c2410_dma_request(unsigned int channel,
                        
            struct s3c2410_dma_client *client,
                        
            void *dev)
            通過(guò)s3c2410_dma_map_channel函數(shù)找到channel對(duì)應(yīng)的通道,并設(shè)置相應(yīng)的通道狀態(tài),申請(qǐng)中斷
            -----------------------------------------------------------------------------------------------------------

            int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
                
            /* if we've only loaded one buffer onto the channel, then chec
                 * to see if we have another, and if so, try and load it so when
                 * the first buffer is finished, the new one will be loaded onto
                * the channel 
            */
            -----------------------------------------------------------------------------------------------------------
            int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
            /* s3c2410_dma_free
             *
             * release the given channel back to the system, will stop and flush
             * any outstanding transfers, and ensure the channel is ready for the
             * next claimant.
             *
             * Note, although a warning is currently printed if the freeing client
             * info is not the same as the registrant's client info, the free is still
             * allowed to go through.
            */

            --------------------------------------------------------------------------------------------------------------
            static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
             
            * stop the channel, and remove all current and pending transfers

            --------------------------------------------------------------------------------------------------------------
            int s3c2410_dma_config(dmach_t channel,
                           
            int xferunit,
                           
            int dcon)
            根據(jù)xferunit設(shè)置通道的控制寄存器
            --------------------------------------------------------------------------------------------------------------
            int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
            根據(jù)flags設(shè)置通道的flags
            --------------------------------------------------------------------------------------------------------------


            int s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op);


            0

            posted on 2012-12-04 08:58 天下 閱讀(822) 評(píng)論(0)  編輯 收藏 引用 所屬分類(lèi): kernel & Driver

            <2012年12月>
            2526272829301
            2345678
            9101112131415
            16171819202122
            23242526272829
            303112345

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(4)

            隨筆分類(lèi)(378)

            隨筆檔案(329)

            鏈接

            最新隨筆

            搜索

            最新評(píng)論

            蜜臀久久99精品久久久久久小说| 久久丝袜精品中文字幕| 久久精品国产亚洲AV大全| 久久99国产综合精品女同| 国产精品久久99| 精品国产婷婷久久久| 亚洲精品无码久久久久AV麻豆| 精品综合久久久久久98| 97热久久免费频精品99| 久久本道久久综合伊人| 久久99精品国产麻豆宅宅| 国产一区二区精品久久| 午夜精品久久久久久影视777| 亚洲人成网亚洲欧洲无码久久 | 综合久久一区二区三区| 婷婷久久香蕉五月综合加勒比| 国产精品久久久天天影视| 久久亚洲国产成人影院网站| 少妇精品久久久一区二区三区| 91久久国产视频| 新狼窝色AV性久久久久久| 99久久精品免费看国产一区二区三区| 亚洲国产成人久久综合区| 国产精品久久久久久| 久久人妻无码中文字幕| 国内精品伊人久久久久影院对白| 精品熟女少妇AV免费久久| 久久国产精品一区| 国产精品99精品久久免费| 亚洲欧美国产精品专区久久| 久久久久国产精品| 亚洲精品乱码久久久久久蜜桃图片 | 精品久久久久久无码专区不卡| 久久不见久久见免费影院www日本| 日韩人妻无码精品久久免费一| 色悠久久久久久久综合网 | 亚洲Av无码国产情品久久| 99久久777色| 麻豆成人久久精品二区三区免费| 婷婷久久综合九色综合绿巨人| 欧美综合天天夜夜久久|