First off, please CC: the mailing list when you email me so others having the same problem can see the response.
Brett McNerney wrote: > Yes I can access the register from a no-os program. There a Xilinx specific > functions to read and write to the registers and those work just fine. I > can run a full test on the register with no problem. Its just when I go to > use linux I can not access the register anymore. > The driver attempted to use is attached along with the sample test program > to run under linux. I added the reg_driver to the Xilinx_gpio makefile. > Got everything to compile and create the kernel but from there the /dev/reg > that should be there is not. Unless you're using devfs (not recommended), /dev/* entries are not created automatically, you need to create them yourself with mknod. Are you using a 2.4 or a 2.6 kernel? It looks like your doing the right thing with ioremap. However, I would break things up a bit. Before wiring it up to a char device, see if you can twiddle the GPIO registers from within the driver itself; then try to get a user space app to twiddle them. Also, for the GPIO core, I'd dump the Xilinx headers and libraries. The register access is so simple that you can just read/write them directly. The xilinx layer just become another layer of abstraction without a whole lot of benefit. Cheers, g. > > -----Original Message----- > From: Grant Likely [mailto:grant.likely at secretlab.ca] > Sent: Monday, January 02, 2006 10:59 PM > To: Brett McNerney > Cc: linuxppc-embedded at ozlabs.org > Subject: Re: Custom Driver > > Brett McNerney wrote: > >>I am need to create a driver to interface to custom hardware on a ml403 >>board. I am first trying to just create a ipif register bank and access >>the registers from linux but am not having any luck of yet. Has anyone >>successfully done this and if so explain how or supply a driver to do >>this and how to build it into the kernel? I am new at this and am >>having great difficutly right now. >> >>Thanks for any help anyone can supply > > Can you access your device from a debugger, or a no-os program (like a > bootloader)? Did you call ioremap() to map the physical register > address into virtual memory? Can you give more detail? > > g. > > > > > ------------------------------------------------------------------------ > > /* my driver header file, defines some consts, structs, etc. */ > /* modeled after/simplified from Xilinx's xgpio */ > /* Author: Joey Rios <rios at soe.ucsc.edu> */ > > #ifndef __IMPROVED_DRIVER_H > #define __IMPROVED_DRIVER_H > > #define REG_IOCTL_BASE 'r' > > #define REG_MINOR 23 > > struct reg_ioctl_data > { > int data; > }; > > #define REG_IN _IOWR(REG_IOCTL_BASE, 0, struct reg_ioctl_data) > #define REG_OUT _IOW (REG_IOCTL_BASE, 1, struct reg_ioctl_data) > > #endif > > > > ------------------------------------------------------------------------ > > /* test_gpio.c > * This program will test our driver (based on xgpio) > * Author: Joseph Rios <rios at soe.ucsc.edu> > * Date: 08/04/05 > * > */ > > #include <stdio.h> > #include <errno.h> > #include <fcntl.h> > #include <linux/ioctl.h> > /* Somehow you need to make sure the program can find this: */ > #include "reg_driver.h" > > > int main() > { > int rtn, i; > int gpio_fd = -1; > struct reg_ioctl_data it; > /* Actual value is not important */ > it.data = 812; > > /* Opening */ > gpio_fd = open("/dev/modular_reg", O_RDWR); > if(gpio_fd == -1){ > perror("Couldn't open /dev/reg"); > return 1; > } > printf("Got through opening /dev/reg\n"); > printf("Will write value of it.data (%i) to reg.\n", it.data); > > /* ioctl test */ > > > rtn = ioctl(gpio_fd, REG_OUT, &it); > /* rtn = 0 means success */ > if(!rtn) printf("Woo hoo! ioctl(REG_OUT) worked!\n"); > else perror("Dang, ioctl(REG_OUT) didn't work"); > > /* Again, value isn't important, as long as chagned */ > it.data = 100; > printf("Now changed it.data to %i.\n", it.data); > printf("Will read reg into it.data to see 'it' change.\n"); > > printf("it.data = %i before ioctl(REG_IN)\n", it.data); > rtn = ioctl(gpio_fd, REG_IN, &it); > > if(!rtn) printf("Woo hoo! ioctl(REG_IN) worked!\n"); > else perror("Dang, ioctl(REG_IN) didn't work"); > > printf("it.data = %i after ioctl(REG_IN)\n", it.data); > > /* Closing */ > if(close(gpio_fd)) perror("Couldn't close /dev/reg"); > else printf("Closed /dev/reg\n"); > > return 0; > } > > > > ------------------------------------------------------------------------ > > /* This is a driver for our register IP */ > /* Completely modeled after the xilinx_gpio driver. This > * driver currently doesn't work as a loadable module for > * unknown reasons. I think the ioremap does something > * goofy to it if called at runtime. > */ > > #ifndef __KERNEL__ > #define __KERNEL__ > #endif > > #include <linux/config.h> > #include <linux/module.h> > #include <linux/miscdevice.h> > #include <linux/kernel.h> /* printk() */ > #include <linux/init.h> /* module_{init, cleanup}() */ > #include <linux/slab.h> > #include <asm/system.h> /* maybe don't need? */ > #include <xparameters_ml300.h> > #include <asm/io.h> > #include <asm/uaccess.h> > #include <asm/irq.h> > > #include <xio.h> > #include <xbasic_types.h> > #include "reg_driver.h" > > /* A redefinition to cutdown on some typing later */ > #define REG_BASE XPAR_REGISTER_0_BASEADDR > #define REG_HIGH XPAR_REGISTER_0_HIGHADDR > > /* Some module documentation */ > MODULE_LICENSE("GPL"); > MODULE_AUTHOR("Joey Rios <rios at soe.ucsc.edu>"); > MODULE_DESCRIPTION("Driver for a register device"); > MODULE_SUPPORTED_DEVICE("plb_register"); > > > /* Global variables needed across methods */ > static u32 reg_remapped_address; > const static long remap_size = REG_HIGH - REG_BASE + 1; > > /* open/close do nothing special. inc/dec use count */ > int reg_open (struct inode *inode, struct file *filp) > { > MOD_INC_USE_COUNT; > return 0; > } > > int reg_release (struct inode *inode, struct file *filp) > { > MOD_DEC_USE_COUNT; > return 0; > } > > /* here is where all the i/o happens. arg is assumed to be a pointer > * to the data. currently, that data is a struct reg_ioctl_data. > * this is probably too complicated at the moment and will > * eventually be just an int, but not sure. filp and inode are not > * used here. > */ > static int > reg_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, > unsigned long arg) > { > int temp; > struct reg_ioctl_data reg_data; > > if(copy_from_user(®_data, (void*) arg, sizeof(reg_data))) > return -EFAULT; > > switch(cmd){ > case REG_IN: > reg_data.data = XIo_In32(reg_remapped_address); > if(copy_to_user((struct reg_ioctl_data*)arg, ®_data, > sizeof(reg_data))) > return -EFAULT; > break; > case REG_OUT: > temp = reg_data.data; > XIo_Out32(reg_remapped_address, (u32) temp); > break; > default: > return -ENOIOCTLCMD; > } > return 0; > } > > /* The operations to be registered with this driver */ > struct file_operations reg_fops = { > ioctl: reg_ioctl, > open: reg_open, > release:reg_release, > owner: THIS_MODULE, > }; > > /* For registering a misc device */ > static struct miscdevice miscdev={ > minor:REG_MINOR, > name:"reg", > fops:®_fops, > }; > > /* init will remap the physical address and save the result > * in reg_remapped_address (global to the driver) then will > * register the device as a misc device > */ > static int reg_init_module(void) > { > int rtn; > > reg_remapped_address = (u32) ioremap(REG_BASE, remap_size); > printk(KERN_INFO "%s at 0x%08X mapped to 0x%08X\n", miscdev.name, > REG_BASE, reg_remapped_address); > > rtn = misc_register(&miscdev); > if(rtn) > { > printk(KERN_ERR "%s: Could not register driver. \n", > miscdev.name); > return rtn; > } > return 0; > } > > /* cleanup simply unmaps the address and deregisters the driver */ > static void reg_cleanup_module(void) > { > iounmap(reg_remapped_address); > misc_deregister(&miscdev); > } > > EXPORT_NO_SYMBOLS; > module_init(reg_init_module); > module_exit(reg_cleanup_module); > -- Grant Likely, B.Sc. P.Eng. Secret Lab Technologies Ltd. (403) 663-0761