Re: serial device driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I think you are using LDD2 instead of LDD3 (which covers the latest 2.6 kernel)

Actually the MOD_INC_USE_COUNT macro was used upto 2.4 series to
increase the module count so that the module is not unloaded if it is
in use or so.

But from 2.6 onwards, the unloading of modules in use is prevented
automatically by the kernel. Hence this macro is no longer in use and
is deprecated. In fact almost all instances of the MOD_INC_USE_COUNT
were removed from the Kernel sources of 2.6.10.

Bhanu.

On 7/28/05, Rahul T <gr8rahul@xxxxxxxxx> wrote:
>  hello all,
>   i am newbee. i am trying to write a serial device driver. i saw the
> one in LDD3 by Rubino. I coded the driver but now it is giving me
> following error
> error =>
> 
>  root@rahul:/home/rahul/driver # make
> make -C /usr/src/linux-2.6.10 SUBDIRS=/home/rahul/driver modules
> make[1]: Entering directory `/usr/src/linux-2.6.10'
>  CC [M]  /home/rahul/driver/tiny1.o
> /home/rahul/driver/tiny1.c: In function `tiny_open':
> /home/rahul/driver/tiny1.c:72: error: `MOD_INC_USE_COUNT' undeclared
> (first use in this function)
> /home/rahul/driver/tiny1.c:72: error: (Each undeclared identifier is
> reported only once
> /home/rahul/driver/tiny1.c:72: error: for each function it appears in.)
> /home/rahul/driver/tiny1.c:78: warning: implicit declaration of function `minor'
> /home/rahul/driver/tiny1.c:78: error: structure has no member named `device'
> /home/rahul/driver/tiny1.c:83: error: `MOD_DEC_USE_COUNT' undeclared
> (first use in this function)
> /home/rahul/driver/tiny1.c:91: error: structure has no member named `device'
> /home/rahul/driver/tiny1.c: In function `do_close':
> /home/rahul/driver/tiny1.c:145: error: `MOD_DEC_USE_COUNT' undeclared
> (first use in this function)
> /home/rahul/driver/tiny1.c: At top level:
> /home/rahul/driver/tiny1.c:223: warning: initialization makes integer
> from pointer without a cast
> /home/rahul/driver/tiny1.c:224: error: unknown field `table' specified
> in initializer
> /home/rahul/driver/tiny1.c:224: warning: initialization from
> incompatible pointer type
> /home/rahul/driver/tiny1.c:230: warning: initialization from
> incompatible pointer type
> make[2]: *** [/home/rahul/driver/tiny1.o] Error 1
> make[1]: *** [_module_/home/rahul/driver] Error 2
> make[1]: Leaving directory `/usr/src/linux-2.6.10'
> make: *** [default] Error 2
> 
> 
> should i try to replace the MOD_.. with a local counter .However doing
> this further generates other errors.
> 
> My code=>
> 
> 
> #include <linux/kernel.h>
> #include <linux/errno.h>
> #include <linux/init.h>
> #include <linux/slab.h>
> #include <linux/tty.h>
> #include <linux/tty_driver.h>
> #include <linux/tty_flip.h>
> #include <linux/module.h>
> #include <linux/sched.h>
> 
> #define DRIVER_VERSION "v1.0"
> #define DRIVER_AUTHOR "RAHUL"
> #define DRIVER_DESC "Tiny TTY driver"
> 
> /* Module information */
> MODULE_AUTHOR( DRIVER_AUTHOR );
> MODULE_DESCRIPTION( DRIVER_DESC );
> MODULE_LICENSE("GPL");
> 
> #define DELAY_TIME              HZ * 2  /* 2 seconds per character */
> #define TINY_DATA_CHARACTER     't'
> 
> #define TINY_TTY_MAJOR          240     /* experimental range */
> #define TINY_TTY_MINORS         255     /* use the whole major up */
> 
> struct tiny_serial {
>        struct tty_struct       *tty;           /* pointer to the tty for this device */
>        int                     open_count;     /* number of times this port has been opened */
>        struct semaphore        sem;            /* locks this structure */
>        struct timer_list       *timer;
> };
> 
> static int                             tiny_refcount;
> static struct tty_driver        tiny_tty_driver;
> static struct tty_struct        *tiny_tty[TINY_TTY_MINORS];
> static struct termios           *tiny_termios[TINY_TTY_MINORS];
> static struct termios           *tiny_termios_locked[TINY_TTY_MINORS];
> static struct tiny_serial       *tiny_table[TINY_TTY_MINORS];   /* initially all NULL */
> 
> 
> static void tiny_timer (unsigned long data)
> {
>        struct tiny_serial *tiny = (struct tiny_serial *)data;
>        struct tty_struct *tty;
> 
>        if (!tiny)
>                return;
> 
>        tty = tiny->tty;
> 
>        if (tty->flip.count >= TTY_FLIPBUF_SIZE)
>                tty_flip_buffer_push(tty);
> 
>        /* add two characters to the tty port */
>        /* this doesn't actually push the data through unless
> tty->low_latency is set */
>        tty_insert_flip_char(tty, TINY_DATA_CHARACTER, 0);
>        tty_insert_flip_char(tty, '\n', 0);
> 
>        tty_flip_buffer_push(tty);
>        tty_schedule_flip (tty);
> 
>        /* resubmit the timer again */
>        tiny->timer->expires = jiffies + DELAY_TIME;
>        add_timer (tiny->timer);
> }
> 
> static int tiny_open (struct tty_struct *tty, struct file * filp)
> {
>        struct tiny_serial *tiny;
>        struct timer_list *timer;
> 
>        MOD_INC_USE_COUNT;
> 
>        /* initialize the pointer incase something fails */
>        tty->driver_data = NULL;
> 
>        /* get the serial object associated with this tty pointer */
>        tiny = tiny_table[minor(tty->device)];
>        if (tiny == NULL) {
>                /* first time accessing this device, let's create it */
>                tiny = kmalloc (sizeof (*tiny), GFP_KERNEL);
>                if (!tiny) {
>                        MOD_DEC_USE_COUNT;
>                        return -ENOMEM;
>                }
> 
>                init_MUTEX (&tiny->sem);
>                tiny->open_count = 0;
>                tiny->timer = NULL;
> 
>                tiny_table[minor(tty->device)] = tiny;
>        }
> 
>        down (&tiny->sem);
> 
>        /* save our structure within the tty structure */
>        tty->driver_data = tiny;
>        tiny->tty = tty;
> 
> 
>        ++tiny->open_count;
>        if (tiny->open_count == 1) {
>                /* this is the first time this port is opened */
>                /* do any hardware initialization needed here */
> 
>                /* create our timer and submit it */
>                if (!tiny->timer) {
>                        timer = kmalloc (sizeof (*timer), GFP_KERNEL);
>                        if (!timer) {
>                                up (&tiny->sem);
>                                MOD_DEC_USE_COUNT;
>                                return -ENOMEM;
>                        }
>                        tiny->timer = timer;
>                }
>                init_timer (tiny->timer);
>                tiny->timer->data = (unsigned long )tiny;
>                tiny->timer->expires = jiffies + DELAY_TIME;
>                tiny->timer->function = tiny_timer;
>                add_timer (tiny->timer);
>        }
> 
>        up (&tiny->sem);
>        return 0;
> }
> 
> static void do_close (struct tiny_serial *tiny)
> {
>        down (&tiny->sem);
> 
>        if (!tiny->open_count) {
>                /* port was never opened */
>                return;
>        }
> 
>        --tiny->open_count;
>        if (tiny->open_count <= 0) {
>                /* The port is being closed by the last user. */
>                /* Do any hardware specific stuff here */
> 
>                /* shut down our timer */
>                del_timer (tiny->timer);
>        }
> 
>        MOD_DEC_USE_COUNT;
> 
>        up (&tiny->sem);
> }
> 
> static void tiny_close (struct tty_struct *tty, struct file * filp)
> {
>        struct tiny_serial *tiny = tty->driver_data;
> 
>        if (!tiny) {
>                return;
>        }
> 
>        do_close (tiny);
> }
> 
> static int tiny_write (struct tty_struct * tty, int from_user, const
> unsigned char *buf, int count)
> {
>        struct tiny_serial *tiny = tty->driver_data;
>        int retval = -EINVAL;
> 
>        if (!tiny) {
>                return -ENODEV;
>        }
> 
>        down (&tiny->sem);
> 
>        if (!tiny->open_count) {
>                /* port was not opened */
>                goto exit;
>        }
> 
>        /* now send the data out the harware port */
>        retval = count;
> 
> exit:
>        up (&tiny->sem);
>        return retval;
> }
> 
> static int tiny_write_room (struct tty_struct *tty)
> {
>        struct tiny_serial *tiny = tty->driver_data;
>        int room;
> 
>        if (!tiny) {
>                return -ENODEV;
>        }
> 
>        down (&tiny->sem);
> 
>        if (!tiny->open_count) {
>                /* port was not opened */
>                return -EINVAL;
>        }
> 
>        /* calculate how much room is left in the device */
>        room = 255;
> 
>        up (&tiny->sem);
> 
>        return room;
> }
> 
> static struct tty_driver tiny_tty_driver = {
>        magic:                  TTY_DRIVER_MAGIC,
>        driver_name:            "tiny_tty",
> #ifndef CONFIG_DEVFS_FS
>        name:                   "ttty",
> #else
>        name:                   "tts/ttty%d",
> #endif
>        major:                  TINY_TTY_MAJOR,
>        num:                    TINY_TTY_MINORS,
>        type:                   TTY_DRIVER_TYPE_SERIAL,
>        subtype:                SERIAL_TYPE_NORMAL,
>        flags:                  TTY_DRIVER_REAL_RAW,
> 
>        refcount:               &tiny_refcount,
>        table:                  tiny_tty,
>        termios:                tiny_termios,
>        termios_locked:         tiny_termios_locked,
> 
>        open:                   tiny_open,
>        close:                  tiny_close,
>        write:                  tiny_write,
>        write_room:             tiny_write_room,
> };
> 
> static int __init tiny_init(void)
> {
>        /* register the tty driver */
>        tiny_tty_driver.init_termios          = tty_std_termios;
>        tiny_tty_driver.init_termios.c_cflag  = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
>        if (tty_register_driver (&tiny_tty_driver)) {
>                printk (KERN_ERR "failed to register tiny tty driver\n");
>                return -1;
>        }
> 
>        printk (KERN_INFO DRIVER_DESC " " DRIVER_VERSION "\n");
> 
>        return 0;
> }
> 
> static void __exit tiny_exit(void)
> {
>        struct tiny_serial *tiny;
>        int i;
> 
>        tty_unregister_driver(&tiny_tty_driver);
> 
>        /* shut down all of the timers and free the memory */
>        for (i = 0; i < TINY_TTY_MINORS; ++i) {
>                tiny = tiny_table[i];
>                if (tiny) {
>                        /* close the port */
>                        while (tiny->open_count)
>                                do_close (tiny);
> 
>                        /* shut down our timer and free the memory */
>                        del_timer (tiny->timer);
>                        kfree (tiny->timer);
>                        kfree (tiny);
>                        tiny_table[i] = NULL;
>                }
>        }
> }
> 
> module_init(tiny_init);
> module_exit(tiny_exit);
> 
> --
> Kernelnewbies: Help each other learn about the Linux kernel.
> Archive:       http://mail.nl.linux.org/kernelnewbies/
> FAQ:           http://kernelnewbies.org/faq/
> 
> 


-- 
The difference between Theory and Practice is more so in Practice than
in Theory.

--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive:       http://mail.nl.linux.org/kernelnewbies/
FAQ:           http://kernelnewbies.org/faq/



[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux