I am writing rtdm driver for PCI1711 card. I got base adress and configured
it. But when I write digtal output or Dac, I can't see changes at those
registers. My Code is below please help me.
#include <rtdm/rtdm_driver.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include "xeno_pci1711_driver.h"
static int __devinit pci1711_probe(struct pci_dev *dev, const struct
pci_device_id *id);
static void __devexit pci1711_remove(struct pci_dev *dev);
int xeno_pci1711_rt_open(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info,
int oflags);
int xeno_pci1711_rt_close(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info);
int xeno_pci1711_rt_ioctl(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info,
int cmd,
void *arg);
//int pci1711_rt_rw(struct rtdm_dev_context
*,rtdm_user_info_t*,void*,size_t);
/**
* module info
*/
MODULE_DESCRIPTION("RTDM driver for PCI1711");
MODULE_AUTHOR("Adil Karaoz");
MODULE_LICENSE("GPL");
/**
* global variables
*/
int first_loop=0;
int ret_loop_val=0;
int isRegister = -1;
/**
* define devices our driver supports
*/
static struct pci_device_id pci1711_ids[]={
{PCI_VENDORID_PLX, PCI_DEVICEID_1711, PCI_SUB_VENDORID_PLX,
PCI_SUB_DEVICEID_1711, 0, 0, 0},
{ }
};
/**
* export pci_device_id structure to user space, allowing hotplug
*/
MODULE_DEVICE_TABLE (pci, pci1711_ids);
/**
* create pci_driver structure,
* and register it in pci1711_driver_init_module,
* unregister in pci1711_exit_module
*/
static struct pci_driver pci1711_driver = {
.name = DRV_NAME,
.id_table = pci1711_ids,
.probe = pci1711_probe,
.remove = __devexit_p(pci1711_remove),
};
/**
* info on our pic1711 card
*/
struct pci1711_context{
/* address in kernel space (virtual memory) */
void __iomem *base_address;
/* physical address */
unsigned long location;
/* size/length of the memory */
unsigned long mem_size;
struct rtdm_device *device;
int dev_id;
};
struct pci1711_context pci1711_struct;
struct pci1711_context *pci1711_card = &pci1711_struct;
/**
* ioctl() implementation
*/
int xeno_pci1711_rt_ioctl(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info,
int cmd,
void *arg)
{
//int err = 0;
int retval = 0;
ioc_param_struct param = {0,0};
ioc_param_struct param2 = {0,0};
switch(cmd) {
case PCI1711_IORESET:
break;
case 2/*PCI1711_DIOWRITE*/:
//printk(KERN_DEBUG "writing to registers\n");
retval = rtdm_safe_copy_from_user(user_info, ¶m,
arg, sizeof(ioc_param_struct));
if(retval == 0) {//success
//@TODO do some checkins, if offset correct...
iowrite32( param.bv, pci1711_card->base_address + 16 +
param.offset );
rtdm_printk(KERN_WARNING "value = %lu port = %u\n", param.bv,
param.offset);
}else{
rtdm_printk(KERN_WARNING "yazilamadi\n");
return -EFAULT;
}
break;
case 1://PCI1711_DIOREAD:
//read from register, write to user
/*if(! capable( CAP_SYS_RAWIO | CAP_SYS_ADMIN ) ){
printk(KERN_WARNING "hata is admin\n");
return -EPERM;
}*/
retval = rtdm_safe_copy_from_user(user_info, ¶m2, arg,
sizeof(ioc_param_struct));
if(retval == 0) {//success
//@TODO some checkins, if offset incorrect...
param.bv = readl( pci1711_card->base_address + 16 + param2.offset );
rtdm_printk(KERN_WARNING "value = %lu port = %u\n", param2.bv,
param2.offset);
if( rtdm_safe_copy_to_user(user_info, arg, ¶m2,
sizeof(ioc_param_struct)) ){
rtdm_printk(KERN_WARNING "hata is copy back\n");
return -EFAULT;
}
}else{
return -EFAULT;
}
break;
default:
printk(KERN_WARNING "default reset = %u write = %lu read = %lu cmd =
%d\n", PCI1711_IORESET, PCI1711_DIOWRITE, PCI1711_DIOREAD, cmd);
return -ENOTTY;
}
return retval;
return 0;
}
/**********************************************************/
/* DRIVER OPERATIONS */
/**********************************************************/
static const struct rtdm_device xeno_pci1711_driver = {
struct_version: RTDM_DEVICE_STRUCT_VER,
device_flags: RTDM_NAMED_DEVICE,// | RTDM_EXCLUSIVE,
context_size: sizeof(struct pci1711_context),
device_name: "",
//don't try to find DEV_FILE in /dev/ - it's not there -
// this is an RTDM internal identifier
//you can find it in /proc/iomem
/* If you do not use kmalloc and kfree, and you made
sure that there is no syscall in the open/close handler, you
can declare the open_rt and close_rt handler.
*/
open_rt: NULL,//xeno_pci1711_rt_open,
open_nrt: xeno_pci1711_rt_open,
ops: {
close_rt: NULL,//xeno_pci1711_rt_close,
close_nrt: xeno_pci1711_rt_close,
ioctl_rt: (void*)xeno_pci1711_rt_ioctl,
ioctl_nrt: NULL,
read_rt: NULL,
read_nrt: NULL,//pci1711_rt_rw,
write_rt: NULL,//pci1711_rt_rw,
write_nrt: NULL,//pci1711_rt_rw,
},
device_class: 0xff00,
device_sub_class: 0, //222, //????
driver_name: DRV_NAME, //informational driver name
peripheral_name: "pci 1711 rtdm", // Informational name
// the device is attached to
provider_name: "Adil Karaoz", // Informational name
};
int xeno_pci1711_rt_open(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info,
int oflags)
{
struct pci1711_context *my_context;
// get the id of the card from the rtdm_device struct
// of the owning device
int dev_id = context->device->device_id;
// get the begin of driver defined context data structure of our driver
my_context = (struct pci1711_context *)context->dev_private;
my_context->dev_id = dev_id;
rtdm_printk( KERN_DEBUG "opening dev with id:%d\n", my_context->dev_id);
return 0;
}
/**
* close named rt device
*
* as of version 0.1 nothing necessary is provided
* by this function
*/
int xeno_pci1711_rt_close(struct rtdm_dev_context *context,
rtdm_user_info_t *user_info)
{
struct pci1711_context *my_context;
// get the context struct
my_context = (struct pci1711_context *)context->dev_private;
printk( KERN_DEBUG "closing... id of dev is %d\n", my_context->dev_id);
return 0;
}
static int pci171x_reset(struct pci_dev *dev)
{
int i;
//#ifdef PCI171X_EXTDEBUG
rtdm_printk( KERN_WARNING "pci1710 EDBG: BGN: pci171x_reset(...)\n");
//#endif
writew(0x30, pci1711_card->base_address + PCI171x_CNTCTRL);
writew(Control_SW, pci1711_card->base_address + PCI171x_CONTROL); // reset
any operations
writeb(0, pci1711_card->base_address + PCI171x_CLRFIFO); // clear FIFO
writeb(0, pci1711_card->base_address + PCI171x_CLRINT); // clear INT request
//start_pacer(dev,-1,0,0); // stop 8254
//devpriv->da_ranges=0;
//if (this_board->n_aochan) {
writeb(0, pci1711_card->base_address + PCI171x_DAREF); // set DACs to 0..5V
writew(0, pci1711_card->base_address + PCI171x_DA1); // set DA outputs to
0V
//devpriv->ao_data[0]=0x0000;
//if (this_board->n_aochan>1) {
writew(0, pci1711_card->base_address + PCI171x_DA2);
//devpriv->ao_data[1]=0x0000;
//}
//}
writew(0xff, pci1711_card->base_address + PCI171x_DO); // digital outputs to
0
writeb(0, pci1711_card->base_address + PCI171x_CLRFIFO); // clear FIFO
writeb(0, pci1711_card->base_address + PCI171x_CLRINT); // clear INT request
//#ifdef PCI171X_EXTDEBUG
rtdm_printk( KERN_WARNING "pci1710 EDBG: END: pci171x_reset(...)\n");
//#endif
return 0;
}
/**
* This function is called by the PCI core when
* it has a struct pci_dev that it thinks this driver wants to control.
*
* Purpose: initialize the device properly
* +set up the rtdm_device structure for this device
*/
static int __devinit pci1711_probe(struct pci_dev *dev, const struct
pci_device_id *id){
/*
* @TODO when initializing module, this function "probe" runs two times
* WHY?
* and as a side effect base address is initialized two times...
*
* the following if-condition avoids two time execution
*/
struct rtdm_device *rtdm_dev;
int ret_val = 0;
uint8_t irq;
rtdm_printk( KERN_WARNING
"bus number: %c function index: %x vendor: %x device: %x class:
%x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, dev->class);
printk( "pci1711 card found!\n" );
//if-condition evaluates to true in the second loop
if(first_loop){
//first_loop =1;
return ret_loop_val;
}
first_loop=1;
//wake up the device
ret_val = pci_enable_device(dev);
if(ret_val!=0){
printk( KERN_WARNING
"xeno_pci1711_driver: function pci_enable_device failed\n");
goto pci_enable_device_err;
}
printk(KERN_DEBUG "device woke up!\n");
//initialization of location and mem_size
pci1711_card->location = pci_resource_start(dev, PCI_1711_BAR & 0xFFFFFFF0
);
pci1711_card->mem_size = pci_resource_len(dev, PCI_1711_BAR & 0xFFFFFFF0
);
//if(pci1711_card->location == 0){
printk( KERN_WARNING "xeno_pc1711_driver: location = %lx mem = %lx\n",
pci1711_card->location, pci1711_card->mem_size);
//}
ret_val = pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
if (!ret_val){
rtdm_printk("interrupt line no:%d",irq);
}
//alloc mem for rtdm structure
rtdm_dev = kmalloc(sizeof(struct rtdm_device), GFP_KERNEL);
if(!rtdm_dev){
printk(KERN_WARNING "xeno_pc1711_driver: kmalloc failed\n");
ret_val = -ENOMEM; //Insufficient storage space is available.
goto kmalloc_err;
}
//copy the structure to the new memory
memcpy(rtdm_dev, &xeno_pci1711_driver, sizeof(struct rtdm_device));
//create filename
snprintf(rtdm_dev->device_name,
RTDM_MAX_DEVNAME_LEN, "%s%d", DRV_NAME, 0 /*i*/);
rtdm_dev->device_id = 0; //i;
//define two other members of the rtdm_device structure
rtdm_dev->proc_name = rtdm_dev->device_name;
if ((ret_val = pci_request_region(dev, PCI_1711_BAR & 0xFFFFFFF0,
rtdm_dev->device_name))){
rtdm_printk(KERN_WARNING "xeno_pci1711_driver: device memory allocation
failed!\n");
ret_val = -EBUSY;
goto request_mem_region_err;
}
printk( KERN_DEBUG "going to map memory to kernel space\n");
//map IO mem to kernel space
pci1711_card->base_address = ioremap( pci1711_card->location,
pci1711_card->mem_size );
//pci1711_card->base_address = (void*)(pci1711_card->base_address &
0xFFFFFFFC);
if(!pci1711_card->base_address){
rtdm_printk(KERN_WARNING "xeno_pci1711_driver: cannot remap memory
region\n");
ret_val = -ENODEV;
goto ioremap_err;
}
rtdm_printk(KERN_DEBUG "base addr...@length is %p @ %lx \n",
pci1711_card->base_address, pci1711_card->mem_size);
ret_val = rtdm_dev_register(rtdm_dev);
if(ret_val < 0){
printk(KERN_WARNING "xeno_pci1711_driver: cannot register device\n");
goto dev_register_err;
}
pci1711_card->device = rtdm_dev;
ret_val = pci_set_mwi (dev);
if( ret_val < 0 ){
printk(KERN_WARNING "xeno_pci1711_driver: pci_set_mwi error\n");
}
pci171x_reset(dev);
//outw( 0xff, pci1711_card->location + 16 );
return ret_val;
//clean up code in case of errors
dev_register_err:
iounmap(pci1711_card->base_address);
ioremap_err:
release_mem_region(pci1711_card->location,
pci1711_card->mem_size);
request_mem_region_err:
kfree(rtdm_dev);
kmalloc_err:
pci_enable_device_err:
//to get the same ret_val in the second unwanted loop...
ret_loop_val = ret_val;
return ret_val;
}
static void __devexit pci1711_remove(struct pci_dev *dev){
//@TODO:when removing module/driver this function runs two times
//WHY?
//the next if condition avoids executing the body of the function
//more than one time. if-condition evaluates to true in the second
//loop.
if(!first_loop){
//first_loop=0;
return;
}
first_loop=0;
printk( KERN_DEBUG "removing...\n" );
//remove char device from the system
//unregister RTdriver
if( pci1711_card->device != NULL )
rtdm_dev_unregister(pci1711_card->device, 1000);
if( pci1711_card->location != 0 ){
printk( KERN_DEBUG "removing base addr...@lenght %p @ %lx\n",
pci1711_card->base_address, pci1711_card->mem_size);
//release virtual memory
iounmap(pci1711_card->base_address);
pci_release_region(dev, PCI_1711_BAR & 0xFFFFFFF0 );
pci_clear_mwi(dev);
}
//free allocated memory
if( pci1711_card->device != NULL )
kfree(pci1711_card->device);
}
/**
* Init module function
*/
static int pci1711_driver_init_module(void){
static int ret_val;
printk( KERN_DEBUG "Module pci1711_driver init\n" );
ret_val = pci_register_driver(&pci1711_driver);
isRegister = ret_val;
if( isRegister < 0 ){
printk("PCI-1711 NOT register \n");
return(-EIO);
}
//pci1711_probe( pcidev, pcidev->driver->id_table );
return ret_val;
}
/**
* Exit module function
*/
static void pci1711_driver_exit_module(void){
printk( KERN_DEBUG "Module pci1711_driver exit\n" );
if( isRegister >= 0 ){
pci_unregister_driver(&pci1711_driver);
//pci1711_remove(pcidev);
}
}
module_init(pci1711_driver_init_module);
module_exit(pci1711_driver_exit_module);
_______________________________________________
Xenomai-help mailing list
[email protected]
https://mail.gna.org/listinfo/xenomai-help