• <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傳輸,需要一下七個步驟:

            一:
            /* 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ù)大?。?/span>0:byte 1:half word 2:word

            每個 DMA 通道都有 
            9 個控制寄存器(4 個通道 DMA 控制器共計(jì) 36 個寄存器)。
            6 個寄存器用來控制 DMA 傳輸,其他三個監(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完成后會調(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ū)動中,傳遞的是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í)際獲得兩個地址,
            1、函數(shù)的返回值是一個void *,代表緩沖區(qū)的內(nèi)核虛擬地址
            2、相關(guān)的總線地址,保存在dma_handle中
                
            dma關(guān)心的是總線地址。
            物理地址與總線地址
            1) 物理地址是與CPU相關(guān)的。在CPU的地址信號線上產(chǎn)生的就是物理地址。在程序指令中的虛擬地址經(jīng)過段映射和頁面映射后,就生成了物理地址,這個物理地址被放到CPU的地址線上。
            2) 總線地址,顧名思義,是與總線相關(guān)的,就是總線的地址線或在地址周期上產(chǎn)生的信號。外設(shè)使用的是總線地址。
            3) 物理地址與總線地址之間的關(guān)系由系統(tǒng)的設(shè)計(jì)決定的。在x86平臺上,物理地址與PCI總線地址是相同的。在其他平臺上,也許會有某種轉(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請求,當(dāng)dma通道可用的時候通過s3c2410_dma_loadbuffer開始一次傳輸,傳輸完成后會產(chǎn)生irq中斷。其dma的中斷服務(wù)函數(shù)中會繼續(xù)啟動dma請求隊(duì)列中的請求,傳輸剩下的數(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 會調(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ù)的說明。供自己日后參考。
            --------------------------------------------------------------------------------------
            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;
            這幾條語句,為什么用memcpy初始化為了dma_sel,而又要用再分配的nmap結(jié)構(gòu)去給dma_sel賦值。其答案是為了保險,因?yàn)閐ma_sel 中的map成員是個指針。對指針的操作是要很小心的。這里在此函數(shù)中重新定義一個指針變量,并指向它,就是為了防止別處定義的指針被撤消而造成越界訪問。其實(shí)我認(rèn)為這沒有必要的。

            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對應(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)
            通過s3c2410_dma_map_channel函數(shù)找到channel對應(yīng)的通道,并設(shè)置相應(yīng)的通道狀態(tài),申請中斷
            -----------------------------------------------------------------------------------------------------------

            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) 評論(0)  編輯 收藏 引用 所屬分類: kernel & Driver

            <2011年10月>
            2526272829301
            2345678
            9101112131415
            16171819202122
            23242526272829
            303112345

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            留言簿(4)

            隨筆分類(378)

            隨筆檔案(329)

            鏈接

            最新隨筆

            搜索

            最新評論

            四虎国产精品免费久久| 欧美日韩久久中文字幕| 色8久久人人97超碰香蕉987| 久久亚洲精品无码播放| 久久精品国产精品青草app| 色综合久久无码五十路人妻| 久久亚洲电影| 欧美午夜A∨大片久久 | 精品久久久久久无码人妻热 | 成人久久久观看免费毛片| 久久婷婷色综合一区二区| 亚洲精品NV久久久久久久久久 | 亚洲av日韩精品久久久久久a| 久久精品卫校国产小美女| 国产亚洲美女精品久久久2020| 久久天天躁狠狠躁夜夜躁2014| 国内精品伊人久久久久妇| 一本色综合久久| 亚洲精品无码久久久| 欧美精品国产综合久久| 狠狠色丁香婷婷久久综合五月 | 狠狠色综合久久久久尤物| 精品久久久久久无码免费| 亚洲精品99久久久久中文字幕 | 久久久久亚洲精品天堂久久久久久| 国产精品久久久久久久久久免费| 久久99精品久久久久久秒播| 天天影视色香欲综合久久| 欧美日韩精品久久久免费观看| 亚洲中文字幕无码久久精品1 | 亚洲国产香蕉人人爽成AV片久久| 免费精品久久天干天干| 国产精品久久久久…| 久久WWW免费人成—看片| 国产精品久久久久久久人人看| 久久国产高潮流白浆免费观看| 国产精品久久久天天影视香蕉| 久久久久久久免费视频| 99久久精品毛片免费播放| 久久久人妻精品无码一区| 久久国产精品一国产精品金尊|