Windows XP Windows 7 Windows 2003 Windows Vista Windows教程綜合 Linux 系統教程
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟件教程
 Windows教程網 >> Linux系統教程 >> Linux教程 >> Linux DMA的platform

Linux DMA的platform

日期:2017/2/7 14:39:27      編輯:Linux教程
 

/* linux/arch/arm/plat-s5p/s3c-pl330.c
*
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
* Jaswinder Singh <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/


#include <linux/init.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>


#include <asm/hardware/pl330.h>


#include <asm/dma.h>


#include <mach/dma.h>


#include <plat/s3c-pl330-pdata.h>


struct s3c_pl330_dmac {
struct pl330_info *pi;
/* Number of channels currently busy */
unsigned busy_chan;
/* To attach to the global list of DMACs */
struct list_head node;
/* List of IDs of peripherals this DMAC can work with */
enum dma_ch *peri;
/* Pool to quickly allocate xfers for all channels in the dmac */
struct kmem_cache *kmcache;
};


struct s3c_pl330_xfer {
/* To attach to the list of xfers on a channel */
struct list_head node;
/* Owner channel of this xfer */
struct s3c_pl330_chan *chan;
/* Xfer ID provided by the client */
void *token;


/* Xfer for PL330 core */
struct pl330_xfer px;
};


struct s3c_pl330_chan {
/* ID of the peripheral that this channel can communicate with */
enum dma_ch id;
/* To attach to the global list of channels */
struct list_head node;
/* Pointer to the last submitted pl330_req to PL330 core */
struct pl330_req *lrq;


/* To manage list of xfers enqueued */
struct list_head xfer_list;
/* Always points to the xfer at the front of queue */
struct s3c_pl330_xfer *xfer_head;


/* Pointer to the DMAC that manages this channel,
* NULL if the channel is available to be acquired.
*/
struct s3c_pl330_dmac *dmac;


/* Token of a hardware channel thread of PL330 DMAC
* NULL if the channel is available to be acquired.
*/
void *pl330_chan_id;


/* Two requests to communicate with the PL330 engine */
struct pl330_req req[2];


/* Client of this channel
* NULL if the channel is available to be acquired.
*/
struct s3c2410_dma_client *client;
/* Callback function to the client */
s3c2410_dma_cbfn_t callback_fn;
/* Options specified by the client */
unsigned int options;
struct pl330_reqcfg rqcfg;
/* Address provided via s3c2410_dma_devconfig */
unsigned long sdaddr;
};


/* All DMACs in the platform */
static LIST_HEAD(dmac_list);


/* All channels to peripherals in the platform */
static LIST_HEAD(chan_list);


/* Since we add resources(DMACs and Channels) to the global pool,
* we need to guard access to the resources using a global lock
*/
static DEFINE_SPINLOCK(res_lock);


/* Returns the channel with ID 'id' in the chan_list */
static struct s3c_pl330_chan *id_to_chan(const enum dma_ch id)
{
struct s3c_pl330_chan *ch;


list_for_each_entry (ch, &chan_list, node)
if (ch->id == id)
return ch;


return NULL;
}


/* Allocate a new channel with ID 'id' and add to chan_list */
static void chan_add(const enum dma_ch id)
{
struct s3c_pl330_chan *ch = id_to_chan(id);


/* Return if the channel already exists */
if (ch)
return;


ch = kmalloc(sizeof(*ch), GFP_KERNEL);
/* Return silently to work with other channels */
if (!ch)
return;


ch->id = id;
ch->dmac = NULL;


list_add_tail(&ch->node, &chan_list);
}


/* If the channel is not yet acquired by any client */
static bool chan_free(struct s3c_pl330_chan *ch)
{
if (!ch)
return false;


/* Channel points to some DMAC only when it's acquired */
return ch->dmac ? false : true;
}


/*

Copyright © Windows教程網 All Rights Reserved