LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Kernel (http://www.linuxquestions.org/questions/linux-kernel-70/)
-   -   uclinux custom device driver not loading, possibly multiple problems (http://www.linuxquestions.org/questions/linux-kernel-70/uclinux-custom-device-driver-not-loading-possibly-multiple-problems-559474/)

godzilla 06-05-2007 09:26 PM

uclinux custom device driver not loading, possibly multiple problems
 
I am pretty new at this, and I have been reading all I can, but I can't seem to put all of the pieces together. Any help is greatly appreciated.

I am trying to write a simple driver called io1, for uClinux, targetting a Coldfire 5282LITE board, and I want it to load on boot. It never has to unload for this app.

The result so far (when loaded onto the board) is that io1 exists in /dev, but it does not exist in /proc/devices or /proc/modules. Also, the open("/dev/io1", O_RDWR) command in the c app that tries to use the driver fails.

This is what I have done:

1. place IO1 folder in linux-2.6.x/drivers/char
IO1 folder contains Makefile,io1.c (source of both shown below)

2. Add option for IO1 to menuconfig
edit linux-2.6.x/drivers/char/Kconfig, add the lines (before config VT):
----
config CONFIG_IO1
bool 'IO1 custom driver' if EMBEDDED
default y
----

3. edit linux-2.6.x/drivers/char/Makefile, add:
----
#ifdef CONFIG_IO1
obj-y += IO1/io1.o
#endif
----

4. tell linux to initialize the driver on boot
----
#ifdef CONFIG_IO1
extern void IO1_init(void);
#endif
----
#ifdef CONFIG_IO1
IO1_init();
#endif
----
at appropriate places
Add above text to drivers/char/mem.c, the init call should go in the chr_device_init() function, the extern at the top

5. edit vendors/Freescale/5282LITE/Makefile, add
----
io1,c,62,0 \
----
under ppp,c,108,0 (note beginning tab and ending slash), there IS one driver after this line (hence the \) note that linux-2.6.x/Documentation/devices.txt specifies major number 62 to be local/experimental use

6. make the image
sudo make menuconfig
verify device driver->char drivers->IO1 custom driver is checked also verify loadable module support:-> enable loadable module support is checked also verify loadable module support:-> enable module unloading is checked sudo make dep sudo make romfs sudo make clean sudo make
_________________

some command traces:

/proc> cat devices
Character devices:
1 mem
2 pty
3 ttyp
4 ttyS
5 /dev/tty
5 /dev/console
10 misc
13 input
90 mtd

Block devices:
1 ramdisk
31 mtdblock

/proc> cat modules

/proc> ls -C /dev
Can console cua0 cua1
io1 ipsec kmem mem
mtd0 mtd1 mtd2 mtdblock0
mtdblock1 mtdblock1 null ppp
ptyp0 ptyp1 ptyp2 ptyp3
ptyp4 ptyp5 ptyp6 ptyp7
ptyp8 ptyp9 ptypa ptypb
ptypc ptypd ptype ptypf
ram0 ram1 ram2 ram3
random rom0 rom1 rom2
rom3 rom4 rom5 rom6
rom7 rom8 rom9 tty
tty0 tty1 tty2 tty3
ttyS0 ttyS1 ttyp0 ttyp1
ttyp2 ttyp3 ttyp4 ttyp5
ttyp6 ttyp7 ttyp8 ttyp9
ttypa ttypb ttypc ttypd
ttype ttypf urandom zero


Notice io1 on the 2nd output line of ls -C /dev
_________________

If I remove the #ifdef and #endif lines from step 4, I get a compile error - reference to undefined function IO_init(). I have no idea why CONFIG_IO1 might not be set, and I have no idea why, even if it was, I would get the reference to undefined function error.
_________________
Makefile (yes, just one line)

obj-m := io1.o

_________________
io.c

#include <linux/slab.h>
#include <linux/module.h>
#include <asm/io.h>
#include <linux/poll.h>
#include <linux/init.h>


#define IO1_MAJOR 62

#define OUTPORT 0x40100010
#define OUTDIR 0x40100024
#define OUTMOD 0x4010005B
//#define OUTMEM *((const volatile unsigned byte *)(0x40020000))


static ssize_t IO1_write(struct file *file, const char *buf, size_t count, loff_t *ppos) {
u8 data;

if (copy_from_user(&data, (u8 *)buf, 1)) return -EFAULT; printk("WRITE Data from user %x hex\n", data); outb(data, OUTPORT); //OUTMEM = data; //writeb(data, OUTPORT); return 1; }

static ssize_t IO1_read(struct file *file, char *buffer, size_t count, loff_t *ppos) {
u8 data;

data = inb(OUTPORT);

printk("data = %x hex\n", data); // for debugging only

// transfer data from kernel address space to user address space

if(copy_to_user( buffer, &data, sizeof(u8))) return -EFAULT;

return 0;
}

static int IO1_open(struct inode * inode, struct file * file) {
printk("io1 Driver open: Usage = %d\n", MOD_IN_USE); MOD_INC_USE_COUNT; return 0; }

static int IO1_release(struct inode * inode, struct file * file) { MOD_DEC_USE_COUNT;
printk("io1 driver release: Usage = %d\n", MOD_IN_USE); return 0; }

struct file_operations IO1_fops = {
owner: THIS_MODULE,
open: IO1_open,
release: IO1_release,
write: IO1_write,
read: IO1_read
};



int __init IO1_init (void)
{
u8 data;
if (register_chrdev(IO1_MAJOR,"io1",&IO1_fops)) {
printk("io1 driver: Failed to get major %d\n", IO1_MAJOR); return -EIO; } printk("Registered device io1: major %d\n",IO1_MAJOR);

data=0x00;
printk("WRITE Port Mode: %x hex\n", data); outb(data, OUTMOD);

data=0x0F;
printk("WRITE Data Direction: %x hex\n", data); outb(data, OUTDIR);

return 0;
}

static void __exit IO1_cleanup (void)
{
printk("Freed resources: MOD_IN_USE = %d\n", MOD_IN_USE); unregister_chrdev(IO1_MAJOR,"My_Driver");
printk("Unregistered device io1: major %d\n",IO1_MAJOR); }


module_init(IO1_init);
module_exit(IO1_cleanup);

MODULE_LICENSE("GPL");

EXPORT_NO_SYMBOLS;

_________________
the code that uses the driver, toggle_pins.c

/*
* File: toggle_pins.c
* Purpose: Toggle some pins to test operation
*
* Notes:
*/

#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include "alwaysInclude/mcf5282.h"

int toggle_pins(int k)
{
unsigned char data;
int handle;

if (k<5)
data = 0xFF;
else
data = 0x00;

handle = open("/dev/io1", O_RDWR);
if(handle > 0)
printf("io1 opened %d\n", handle);

else
{
printf("Error opening io1\n");
return -1;
}

if(write(handle, &data, 1) < 0)
printf("Error writing io1\n");
else
printf("WRITE SUCCESSFUL\n");

printf("NOTHING HAPPENING\n");

return 1;
}
_________________

I know that's a lot, and I apologize. I am trying to give everything I can to help anyone help me.
Does ANYBODY have ANY thoughts on this? I have been spinning my wheels way too long. Thank you in advance!

Matt

Mara 06-08-2007 03:58 PM

Are you writing a module or code linked with the kernel/any other module? It's not clear here. And that's the reason of your problems, I think.

godzilla 06-08-2007 04:42 PM

Hmm... my novice sense tells me that I do not know how to answer this question. I will try to educate myself on this matter and respond when possible. Thank you so far!

Mara 06-10-2007 02:16 PM

I'll explain it a bit, so it will be easier for you to search. If you add your code to the kernel, you can use all kernel structures and functions. The code exists even if it's not needed, takes RAM and so on.

Module can only use functions and structures that are exported from the kernel. It's more stand-alone and loaded only when needed.

godzilla 06-15-2007 12:08 PM

kernel/module
 
I would say, then that for this application, it is best to compile this as part of the kernel. Resources are not an issue, and this driver should be as hidden as possible to any future user (loading/unloading is not desirable). AND that may make it easier to use the kernel functions, as you say.

Mara 06-16-2007 05:10 PM

Then remove the module-related macros etc. You also need to find a good place to initialize it (the right moment...)

godzilla 07-15-2007 11:33 AM

macros
 
I can't seem to find much info on drivers that AREN'T modules, and I can't seem to find what portions are module macros.

I assume these things:
#include <linux/module.h>

module_init(IO1_init);
module_exit(IO1_cleanup);

MODULE_LICENSE("GPL");

Do these things look OK for initializing the driver at the beginning of execution if I remove those macros? I am having trouble figuring out what deleting the above lines will actually do, so I think I am missing something.

----
#ifdef CONFIG_IO1
extern void IO1_init(void);
#endif
----
#ifdef CONFIG_IO1
IO1_init();
#endif
----
at appropriate places
Add above text to drivers/char/mem.c, the init call should go in the chr_device_init() function, the extern at the top

Mara 07-15-2007 12:41 PM

The difference is mostly in the macros you show: module_init and module_exit. They're wrappers which run your functions and performs some module-related stuff (which you do not need). Remove the include file and the three following lines. Then you have to run IO1_init and IO1_cleanup at appropriate places. Your ifdefs look fine.

godzilla 07-15-2007 12:54 PM

thank you
 
Thank you so much, Mara. Your help is greatly appreciated. I apologize for my noob-ness.

I will try what you said and see what I can do to work with it!

godzilla 07-17-2007 12:07 PM

Still, when I comment out the #ifdefs but leave the functions:

----
//#ifdef CONFIG_IO1
extern int IO1_init(void);
//#endif
----
//#ifdef CONFIG_IO1
i=IO1_init();
//#endif
----

when I make, I get undefined reference to IO1_init. It is not the extern line, but the other one that is causing the error. Note that I did change the extern definition from void to init to match the IO1_init function in the driver, and I placed i= in the second fuctional reference. (i is an int) The error occurs with or without these int changes.

godzilla 07-17-2007 12:46 PM

Of course, I had to comment out the ifdef lines in the char driver makefile also:

#ifdef CONFIG_IO1
obj-y += IO1/io1.o
#endif

Having done this, I get
"drivers/char/IO1/io1.o: No such file: No such file or directory"
on make.

In drivers/char, I have placed a directory called IO1. In this directory, I have the driver source, io1.c, and the Makefile, which is simply 1 line:

obj-m := io1.o

I must have gotten this from one of the tutorials I was trying to follow because I really don't know what it is doing. As such, I also do not know why io1.o does not exist on Make of the entire kernel/file system.

I will worry about why the ifdef's need commented later. If you could help on this, I would once again be very appreciative.

Mara 07-19-2007 03:37 PM

You should add to the Makefile in char/ something like
obj-y := IO1/
Also, change that obj-m to obj-y (to make it always included, for the short time).

godzilla 09-10-2007 06:39 PM

I did try what you said, and I never have gotten this to work. I am going to try a whole different route I think. I do appreciate all of your efforts, though, Mara. Thank you for being so helpful and tolerating a novice!


All times are GMT -5. The time now is 08:10 PM.