Getting the IRQ number (Was: Basic driver devel questions ?)

Guillaume Dargaud dargaud at lpsc.in2p3.fr
Wed Dec 8 21:18:13 EST 2010


Thanks again for your detailed answer,
I'm learning, but not as fast as my colleagues with a deadline want me to !

> The platform code does that. That function create devices on the
> platform bus by examining the device tree. It looks for nodes that are
> compatible with the compatible strings you give it, and treats them as
> busses, ie. creates devices for all child nodes of those nodes.

Is there a way to enable some debug output from it, to see what's going on ?

> > ...hmm I had to "git pull" in order for this to compile your snippet.
> > That's really recent! Unfortunately i need to reflash my device with the
> > new kernel before i can begin testing my module.
> 
> It shouldn't be that recent, what kernel version were you using?

I had to go from 2.6.34 to 2.6.35, xilinx git tree.

> Yes sorry, that's a cut & paste bug, between the old and new style code.

No worries, I knew it was some uncompiled example.

> platform_device_register() creates a device on the platform bus. You
> then write a driver for that device, and register it with
> platform_driver_register(), your driver then attaches to the device.
> 
> In this case though you don't need to call platform_device_register()
> because the device has already been created, using the device tree (by
> of_platform_bus_probe()).

OK, I'll have to remove it from my sample code below.

> In general on powerpc we don't use platform_device_register() much,
> instead things are described in the device tree and devices are created
> for them.
> 
> platform_device_register() tends to be for cases where you can't
> discover or probe a device, but you "know" that it exists.

When you see something in /sys/devices/plb.0/, it means that you don't need 
platform_device_register, right ?

> Yes, "make tags", then use vim :)

Great, that works.


OK, here's the relevant part of my code, ripped directly from your sample, 
with a few additions and different variable names. Why do you think 
xad_driver_probe() is not being called ?


#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/device.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>         // char device
#include <linux/fs.h>
#include <linux/of.h>
#include <linux/interrupt.h>

#define DEVNAME "xps-acqui-data"
#define NAME "xad"              // This is only used for printk

#define SD "{%s %d} "
#define FL , __func__, __LINE__

static dev_t first;
static unsigned int count = 1;
static int my_major = 241, my_minor = 0;
// You must run "mknod /dev/xad c 241 0" in a shell at least once

struct cdev *my_cdev=NULL;
struct platform_device *pdev=NULL;

typedef struct XadDevice {
  struct resource *hw_region;
  struct device *dev;
  int irq;
} tXadDevice;
tXadDevice Xad;

// There should be something in:
// ll /sys/devices/plb.0/c9800000.xps-acqui-data
static const struct of_device_id xad_device_id[] = {                       
        { .compatible     = "xlnx,xps-acqui-data-3.00.a" },     // Must match 
the DTS
        {}
};

  
static irqreturn_t XadIsr(int irq, void *dev_id) {
  printk(KERN_INFO SD "IRQ:%d\n" FL, irq);
  return IRQ_HANDLED;
}

///////////////////////////////////////////////////////////////////////////////
// Platform Bus Support
///////////////////////////////////////////////////////////////////////////////

static int  xad_driver_probe(struct platform_device *device /*,
                            const struct of_device_id *device_id*/ ) {
  struct device_node *dn = device->dev.of_node;
  int rc;

  pr_devel("Probing %s\n", dn->full_name);
  
  Xad.irq = irq_of_parse_and_map(dn, 0);
  rc=request_irq(Xad.irq, XadIsr, IRQF_TRIGGER_RISING  | IRQF_DISABLED, 
"XadIsr", &Xad);
  if (rc) printk(KERN_INFO SD "Failled IRQ request: %d\n" FL, rc);
  
  return 0;
}

static int __devexit xad_driver_remove(struct platform_device *device) {
  printk(KERN_INFO SD "Removing...\n" FL);
  return 0;
}

static struct platform_driver xad_driver = {
  .probe  = xad_driver_probe,
  .remove = xad_driver_remove,
  .driver = {
    .owner = THIS_MODULE,
    .name = "xad-driver",
        .of_match_table = xad_device_id,
  },
};


///////////////////////////////////////////////////////////////////////////////
// This section deals with the /dev/xad device
///////////////////////////////////////////////////////////////////////////////
static int xad_open(struct inode *node, struct file *filep) {
  printk (KERN_INFO SD "OPENING device: %s\n" FL, NAME);
  return 0;
}

static int xad_release(struct inode *node, struct file *filep) {
  printk (KERN_INFO SD "RELEASING device: %s\n" FL, NAME);
  return 0;
}

static int  xad_ioctl(struct inode *node, struct file *filep, unsigned int cmd, 
unsigned long arg) {
  printk (KERN_INFO SD "IOCTL on device: %s, cmd:%d, arg:%lu\n" FL, NAME, cmd, 
arg);
  return 0;
}

static struct file_operations fops = {
  .owner   = THIS_MODULE,
  .open    = xad_open,
  .release = xad_release,
  .ioctl   = xad_ioctl,
};


///////////////////////////////////////////////////////////////////////////////
// Called on insmod
static int __init xad_init(void) {
  int rc=0;
  printk(KERN_INFO SD "Module %s: loading...\n" FL, NAME);
  
  // Deal with the device
  first = MKDEV (my_major, my_minor);
  register_chrdev_region(first, count, DEVNAME);
  my_cdev = cdev_alloc ();
  if (NULL==my_cdev) goto Err;
  
  cdev_init(my_cdev, &fops);
  cdev_add (my_cdev, first, count);

  printk(KERN_INFO SD "Module %s: Major=%d, Minor=%d, Count=%d\n" FL, NAME, 
my_major, my_minor, count);

  // Driver
  rc = platform_driver_register(&xad_driver);
//  rc = platform_driver_probe(&xad_driver, xad_driver_probe);
  if (rc) goto err_plat;

  // Device
  pdev=platform_device_register_simple("xps-acqui-data", -1, NULL, 0);
  if (IS_ERR(pdev)) {
          rc = PTR_ERR(pdev);
          platform_driver_unregister(&xad_driver);
          goto err_plat;
  }


  return 0;

err_plat:
  unregister_chrdev_region(first, count);
Err:
  printk(KERN_ERR SD "Module %s: Failed loading rc=%d\n" FL, NAME, rc);
  return rc;
}

///////////////////////////////////////////////////////////////////////////////
// Called on rmmod
static void xad_exit(void) {
  platform_device_unregister(pdev); pdev=NULL;
  platform_driver_unregister(&xad_driver);
  
  cdev_del (my_cdev); my_cdev=NULL;
  unregister_chrdev_region (first, count);
  printk(KERN_INFO SD "Module %s unloaded\n" FL, NAME);
}

module_init(xad_init);
module_exit(xad_exit);

MODULE_AUTHOR("Guillaume Dargaud");
MODULE_LICENSE("GPL");





And here's the result:

# tail -f /var/log/messages &
# insmod xad.ko
Dec  7 14:42:02 gandalf user.info kernel: [15897.152109] {xad_init 162} Module 
xad: loading...
Dec  7 14:42:02 gandalf user.info kernel: [15897.156665] {xad_init 173} Module 
xad: Major=241, Minor=0, Count=1

# ./xad_test	# A simple prog that opens, does an iocl and closes the device
./xad_test Initialisation
./xad_test Ioctl
./xad_test Closing

Dec  7 14:42:16 gandalf user.info kernel: [15911.160343] {xad_open 130} 
OPENING device: xad
Dec  7 14:42:16 gandalf user.info kernel: [15911.164521] {xad_ioctl 142} IOCTL 
on device: xad, cmd:0, arg:0
Dec  7 14:42:16 gandalf user.info kernel: [15911.173035] {xad_release 136} 
RELEASING device: xad

# rmmod xad
Dec  7 14:42:23 gandalf user.info kernel: [15918.753661] {xad_exit 206} Module 
xad unloaded


And in the dts:

/dts-v1/;
/ {
	...
	plb: plb at 0 {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "xlnx,plb-v46-1.05.a", "xlnx,plb-v46-1.00.a", "simple-
bus";
		ranges ;
		...
		xps_acqui_data_0: xps-acqui-data at c9800000 {
			compatible = "xlnx,xps-acqui-data-3.00.a";
			interrupt-parent = <&xps_intc_0>;
			interrupts = < 0 2 >;
			reg = < 0xc9800000 0x10000 >;
			xlnx,family = "virtex4";
			xlnx,include-dphase-timer = <0x1>;
			xlnx,mplb-awidth = <0x20>;
			xlnx,mplb-clk-period-ps = <0x2710>;
			xlnx,mplb-dwidth = <0x40>;
			xlnx,mplb-native-dwidth = <0x40>;
			xlnx,mplb-p2p = <0x0>;
			xlnx,mplb-smallest-slave = <0x20>;
		} ;
		...
	} ;
	...
}  ;


# ll /sys/devices/plb.0/c9800000.xps-acqui-data/
-r--r--r--    1 root     root        4.0K Dec  7 12:55 devspec
-r--r--r--    1 root     root        4.0K Dec  7 12:55 modalias
-r--r--r--    1 root     root        4.0K Dec  7 12:55 name
lrwxrwxrwx    1 root     root           0 Dec  7 12:55 subsystem -> 
../../../bus/of_platform/
-rw-r--r--    1 root     root        4.0K Dec  7 12:55 uevent

-- 
Guillaume Dargaud
http://www.gdargaud.net/


More information about the Linuxppc-dev mailing list