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: p...@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-d...@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/ _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev