tiny4412 串口驱动分析五 --- LDD3上TTY驱动程序源码

发布时间:2023-06-25  

Makefile:


# Comment/uncomment the following line to disable/enable debugging

#DEBUG = y



# Add your debugging flag (or not) to CFLAGS

ifeq ($(DEBUG),y)

  DEBFLAGS = -O -g -DSCULL_DEBUG # "-O" is needed to expand inlines

else

  DEBFLAGS = -O2

endif


EXTRA_CFLAGS += $(DEBFLAGS)

EXTRA_CFLAGS += -I..


ifneq ($(KERNELRELEASE),)

# call from kernel build system


obj-m    := tiny_tty.o tiny_serial.o


else


#KERNELDIR ?= /lib/modules/$(shell uname -r)/build

KERNELDIR ?= /root/Tiny4412_android_4_1_2/linux-3.0.31

PWD       := $(shell pwd)


default:

    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules


endif


clean:

    rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions


depend .depend dep:

    $(CC) $(EXTRA_CFLAGS) -M *.c > .depend



ifeq (.depend,$(wildcard .depend))

include .depend

endif



tiny_tty.c


/*

 * Tiny TTY driver

 *

 * Copyright (C) 2002-2004 Greg Kroah-Hartman (greg@kroah.com)

 *

 *    This program is free software; you can redistribute it and/or modify

 *    it under the terms of the GNU General Public License as published by

 *    the Free Software Foundation, version 2 of the License.

 *

 * This driver shows how to create a minimal tty driver.  It does not rely on

 * any backing hardware, but creates a timer that emulates data being received

 * from some kind of hardware.

 */


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include



#define DRIVER_VERSION "v2.0"

#define DRIVER_AUTHOR "Greg Kroah-Hartman "

#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        4    /* only have 4 devices */


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;


    /* for tiocmget and tiocmset functions */

    int            msr;        /* MSR shadow */

    int            mcr;        /* MCR shadow */


    /* for ioctl fun */

    struct serial_struct    serial;

    wait_queue_head_t    wait;

    struct async_icount    icount;

};


static struct tiny_serial *tiny_table[TINY_TTY_MINORS];    /* initially all NULL */



static void tiny_timer(unsigned long timer_data)

{

    struct tiny_serial *tiny = (struct tiny_serial *)timer_data;

    struct tty_struct *tty;

    int i;

    char data[1] = {TINY_DATA_CHARACTER};

    int data_size = 1;


    if (!tiny)

        return;


    tty = tiny->tty;


    /* send the data to the tty layer for users to read.  This doesn't

     * actually push the data through unless tty->low_latency is set */

    for (i = 0; i < data_size; ++i) {

        if (!tty_buffer_request_room(tty, 1))

            tty_flip_buffer_push(tty);

        tty_insert_flip_char(tty, data[i], TTY_NORMAL);

    }

    tty_flip_buffer_push(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 *file)

{

    struct tiny_serial *tiny;

    struct timer_list *timer;

    int index;


    /* initialize the pointer in case something fails */

    tty->driver_data = NULL;


    /* get the serial object associated with this tty pointer */

    index = tty->index;

    tiny = tiny_table[index];

    if (tiny == NULL) {

        /* first time accessing this device, let's create it */

        tiny = kmalloc(sizeof(*tiny), GFP_KERNEL);

        if (!tiny)

            return -ENOMEM;


        sema_init(&tiny->sem, 1);

        tiny->open_count = 0;

        tiny->timer = NULL;


        tiny_table[index] = 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);

                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 */

        goto exit;

    }


    --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);

    }

exit:

    up(&tiny->sem);

}


static void tiny_close(struct tty_struct *tty, struct file *file)

{

    struct tiny_serial *tiny = tty->driver_data;


    if (tiny)

        do_close(tiny);

}    


static int tiny_write(struct tty_struct *tty, 

              const unsigned char *buffer, int count)

{

    struct tiny_serial *tiny = tty->driver_data;

    int i;

    int retval = -EINVAL;


    if (!tiny)

        return -ENODEV;


    down(&tiny->sem);


    if (!tiny->open_count)

        /* port was not opened */

        goto exit;


    /* fake sending the data out a hardware port by

     * writing it to the kernel debug log.

     */

    printk(KERN_DEBUG "%s - ", __FUNCTION__);

    for (i = 0; i < count; ++i)

        printk("%02x ", buffer[i]);

    printk("n");

        

exit:

    up(&tiny->sem);

    return retval;

}


static int tiny_write_room(struct tty_struct *tty) 

{

    struct tiny_serial *tiny = tty->driver_data;

    int room = -EINVAL;


    if (!tiny)

        return -ENODEV;


    down(&tiny->sem);

    

    if (!tiny->open_count) {

        /* port was not opened */

        goto exit;

    }


    /* calculate how much room is left in the device */

    room = 255;


exit:

    up(&tiny->sem);

    return room;

}


#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))


static void tiny_set_termios(struct tty_struct *tty, struct ktermios *old_termios)

{

    unsigned int cflag;


    cflag = tty->termios->c_cflag;


    /* check that they really want us to change something */

    if (old_termios) {

        if ((cflag == old_termios->c_cflag) &&

            (RELEVANT_IFLAG(tty->termios->c_iflag) == 

             RELEVANT_IFLAG(old_termios->c_iflag))) {

            printk(KERN_DEBUG " - nothing to change...n");

            return;

        }

    }


    /* get the byte size */

    switch (cflag & CSIZE) {

        case CS5:

            printk(KERN_DEBUG " - data bits = 5n");

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>