arch\arm\mach-zynq\pl330.c
#define DRIVER_NAME "pl330"
/////////////
static struct platform_driver pl330_platform_driver =
{
.probe = pl330_platform_probe, //匹配到的时候调用
.remove =
pl330_platform_remove,
.driver = {
.name = DRIVER_NAME,
.owner =
THIS_MODULE,
},
};
////////////////////
static int __init
pl330_init(void)
{
int status;
pl330_driver_init();
status =
platform_driver_register(&pl330_platform_driver);
PDEBUG("platform_driver_register:
%d\n", status);
return status;
}
module_init(pl330_init);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
*
pl330_driver_init - Initialize the dma_struct array and store the
pointer
* to array
*/
arch\arm\mach-zynq\pl330.c
static void pl330_driver_init(void)
{
unsigned int
i;
PDEBUG("inside pl330_driver_init, dma_chan is %x\n",
(unsigned
int)dma_chan);
driver_data.dma_chan = dma_chan;
memset(dma_chan, 0, sizeof(dma_chan[MAX_DMA_CHANNELS]));
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
dma_chan[i].d_ops =
&pl330_ops;
isa_dma_add(i, dma_chan
+ i);
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
*
pl330_platform_probe - Platform driver probe
* @pdev: Pointer to the
platform device structure
*
* Returns 0 on success, negative error
otherwise
*/
arch\arm\mach-zynq\pl330.c
static int __devinit pl330_platform_probe(struct platform_device
*pdev)
{
int pdev_id;
if (!pdev) {
dev_err(&pdev->dev, "pl330 probe called
with NULL param.\n");
return -ENODEV;
}
PDEBUG("pl330 driver probing dev_id %d\n",
pdev->id);
pdev_id = 0;
if (pdev->id < 0) {
pdev_id = 0;
}
else if (pdev->id < MAX_DMA_DEVICES) {
pdev_id = pdev->id;
}
else {
dev_err(&pdev->dev,
"pl330 device id exceeds the
supported number.\n");
return -ENODEV;
}
pl330_init_device_data(pdev_id, pdev);
/* assume the init_device_data is invoked before this point
*/
pl330_init_channel_static_data(pdev_id);
/* setup the default burst size
*/
pl330_set_default_burst_size(pdev_id);
/* request irq */
if (pl330_request_irq(pdev_id)) {
pl330_release_io(pdev, pdev_id);
return
-1;
}
printk(KERN_INFO "pl330 dev %d probe success\n",
pdev->id);
return
0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
*
pl330_request_irq - set up the interrupt handler for the
corresponding
* device. It sets up all the interrupt for all the channels of
that
* device. It also sets the the fault interrupt handler for the
device.
* @dev_id: device id.
*
* Returns 0 on success, otherwise on
failure
*/
int pl330_request_irq(unsigned int dev_id)
{
unsigned int
irq;
unsigned int irq2;
struct pl330_channel_static_data
*channel_static_data;
struct pl330_device_data *device_data
=
driver_data.device_data + dev_id;
int status;
PDEBUG("PL330 requesting irq for device %d\n",
dev_id);
channel_static_data = driver_data.channel_static_data
+
device_data->starting_channel;
irq = device_data->fault_irq;
/* set up the fault irq */
status = request_irq(irq, pl330_fault_isr,
IRQF_DISABLED, DRIVER_NAME, device_data);
//
irq是要申请的硬件中断号。handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。
irqflags是中断处理的属性,若设置了IRQF_DISABLED
(老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序是快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;若设置了IRQF_SHARED
(老版本中的SA_SHIRQ),则表示多个设备共享中断,若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。(这几个flag是可以通过或的方式同时使用的)
devname设置中断名称,通常是设备驱动程序的名称
在cat
/proc/interrupts中可以看到此名称。 dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。
////
if (status) {
printk(KERN_ERR "PL330 request fault irq %d
failed %d\n",
irq, status);
return -1;
} else
{
PDEBUG("PL330 request fault irq %d successful\n",
irq);
}
for (irq = device_data->starting_irq;
irq != 0
&& irq <= device_data->ending_irq; irq++) {
/* set up the done irq */
status = request_irq(irq,
pl330_done_isr,
IRQF_DISABLED, DRIVER_NAME,
channel_static_data);
if (status) {
printk(KERN_ERR
"PL330 request done irq
%d failed %d\n",
irq, status);
goto
req_done_irq_failed;
} else {
channel_static_data->irq =
irq;
PDEBUG("PL330 request done irq %d successful\n", irq);
}
channel_static_data++;
}
for (irq = device_data->starting_irq1;
irq != 0 && irq
<= device_data->ending_irq1; irq++) {
/* set up the done irq */
status = request_irq(irq,
pl330_done_isr,
IRQF_DISABLED, DRIVER_NAME,
channel_static_data);
if (status) {
printk(KERN_ERR
"PL330 request done irq
%d failed %d\n",
irq, status);
goto
req_done_irq1_failed;
} else {
channel_static_data->irq =
irq;
PDEBUG("PL330 request done irq %d successful\n", irq);
}
channel_static_data++;
}
return 0;
req_done_irq1_failed:
for (irq2 =
device_data->starting_irq1;
irq2 < irq;
irq2++)
free_irq(irq2, channel_static_data);
irq = device_data->ending_irq + 1;
req_done_irq_failed:
for (irq2 =
device_data->starting_irq;
irq2 < irq;
irq2++)
free_irq(irq2, channel_static_data);
free_irq(device_data->fault_irq, channel_static_data);
return
-1;
}
//////////////////////////////////////////////////////
/**
*
pl330_platform_remove - called when the platform driver is unregistered
*
@pdev: Pointer to the platform device structure
*
* Returns 0 on
success, negative error otherwise
*/
static int pl330_platform_remove(struct platform_device
*pdev)
{
int pdev_id;
if (!pdev) {
dev_err(&pdev->dev, "pl330 remove called
with NULL param.\n");
return -ENODEV;
}
PDEBUG("pl330 driver removing %d\n", pdev->id);
pdev_id = 0;
if (pdev->id < 0) {
pdev_id = 0;
}
else if (pdev->id < MAX_DMA_DEVICES) {
pdev_id = pdev->id;
}
else {
dev_err(&pdev->dev,
"pl330 device id exceeds the
supported number.\n");
return -ENODEV;
}
pl330_free_irq(pdev_id);
pl330_release_io(pdev, pdev_id);
return
0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ?