memory mapped IO in kernel mode

I'm working on a device driver for a 2.4 kernel and I'm having a heck of a hard time.... I've never written a kernel module before, so it's an uphill struggle. By way of background, I am working with Linux Device Drivers, 2nd ed.... And I have a similar driver written for x86 architecture that I am using as a guide.

The hardware is controlled via memory mapped registers at 0x11e0104 -

0x11e0107. From what I've ben able to gather, I need to ioremap this and use the handle returned by ioremap for readb and readw...

But... I am thoroughly confused by the kernel mode memory addressing and how it pertains to the ARM architecture.

My init function is this:

#define TSDIO24region 0x11e00104 #define TSDIO24length 4

static char *mem_virt_addr;

int init_TSgpio(void) { int result;

printk("Hello world.\n");

if (check_mem_region(TSDIO24region, TSDIO24length)) { printk("TSgpio: memory already in use\n"); return -EBUSY; } request_mem_region(TSDIO24region, TSDIO24length, "TSDIO24gpio");

if( (result = register_chrdev(TSDIO24major, "TSDIO24", &tsdio24_fops)) < 0) { printk(KERN_WARNING "tsdio24: can't get major %d\n",TSDIO24major); return result; } mem_virt_addr = ioremap(TSDIO24region, TSDIO24length); return 0; }

and my read function is this:

static ssize_t tsdio24_read(struct file *file, char *buf, size_t, length, loff_t *ppos) { printk("0x%02x %02x %02x %02x\n", readb(mem_virt_addr), readb(mem_virt_addr+1), readb(mem_virt_addr+2), readb(mem_virt_addr+3)); return 0; }

While the read function does in fact spit out 4 bytes on `cat /dev/mydev`, they appear to be unrelated to the memory location I want. I did try this with page-aligned ioremap; AFAICT I got the same (wrong) memory area.

I am completely confused by the various 'adjustments' to the memory addresses that I read about... Should I subtract 0x80000000 from the above before I ioremap? Does ioremap have to be page aligned? What *are* the arguments to ioremap? It doesn't seem to be documented anywhere in any detail.

So... How does one do memory mapped IO on an ARM platform in kernel mode?

The driver, BTW, is fairly simple - it will implement IRQs for GPIO pins. I was expecting a struggle over the IRQ code, but this has stumped me early.... :-(

TIA,

--Yan

--
  o__
  ,>/'_          o__
  (_)\(_)        ,>/'_        o__
Yan Seiner, PE  (_)\(_)       ,>/'_     o__
Certified Personal Trainer   (_)\(_)    ,>/'_        o__
Licensed Professional Engineer         (_)\(_)       ,>/'_
Who says engineers have to be pencil necked geeks?  (_)\(_)
Reply to
Captain Dondo
Loading thread data ...

How can you tell you are in the right memory area, do you have a probe (or similar) you can use to read the same address back ?

You should pass the actual physical address into ioremap, the kernel's implementation for ARM should do any messing required to translate it for you.

Reply to
Geronimo W. Christ Esq

I don't see anything wrong with your code. Are you positive about the base address? I infer from your driver names that you are using a TS-DIO24. If you are also using a TS ARM processor board, wouldn't the base address be 0x011e0000?

If you have access to a 'scope or logic analyzer, you might want to probe the device you are reading and see if the I/O read line is going active.

Steve

------------------------------------------------------------------------ Steve Schefter phone: +1 705 725 9999 x26 The Software Group Limited fax: +1 705 725 9666

642 Welham Road, Barrie, Ontario CANADA L4N 9A1 Web:
formatting link
Reply to
steve_schefter

Thanks, guys. It turns out that on an arm w/ 2.4 kernel, you need __ioremap, not ioremap.... Go figure.

And yes, the base address wasn't right, but that was not the issue... All is almost well - at least now I am happily making kernel OOPSes... :-)

--Yan

Reply to
Captain Dondo

Strange. ioremap() should be #defined to call __ioremap with the flags parameter set to zero. I use ioremap_nocache() (calls __ioremap() with flags set to 1). You might want to try that as it'll be more portable than __ioremap().

Fun, fun, fun.

Regards, Steve

------------------------------------------------------------------------ Steve Schefter phone: +1 705 725 9999 x26 The Software Group Limited fax: +1 705 725 9666

642 Welham Road, Barrie, Ontario CANADA L4N 9A1 Web:
formatting link
Reply to
steve_schefter

The issue is that each board can re-define ioremap via __arch_ioremap in include/asm-arm/arch-???/io.h . (Something I learned from this... Reading kernel headers is not something I do for fun.)

So for mine (an EP93xx board), the comments read:

/*

  • ioremap and friends.
*
  • ioremap takes a PCI memory address, as specified in
  • linux/Documentation/IO-mapping.txt. If you want a
  • physical address, use __ioremap instead.
*/
--
  o__
  ,>/'_          o__
  (_)\(_)        ,>/'_        o__
Yan Seiner, PE  (_)\(_)       ,>/'_     o__
Certified Personal Trainer   (_)\(_)    ,>/'_        o__
Licensed Professional Engineer         (_)\(_)       ,>/'_
Who says engineers have to be pencil necked geeks?  (_)\(_)
Reply to
Captain Dondo

Yeah, I saw that comment too. But the code in the headers doesn't seem to match the comment. Also, If you take a look at the referenced IO-mapping.txt file, it doesn't say that ioremap() is for PCI only. It does however say that it's useful for beyond the 640-1MB area so that may be where the idea of using ioremap() for PCI-space came from.

I've only seen __arch_ioremap turned around to __ioremap. Perhaps yours is different though.

Regards, Steve

Reply to
steve_schefter

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.