来源:LINUX设备驱动程序第三版配套源码

Table of Contents

tiny_serial.c

tiny_tty.c

makefile


tiny_serial.c

/** Tiny Serial 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 serial driver.  It does not rely on* any backing hardware, but creates a timer that emulates data being received* from some kind of hardware.*  这个驱动程序展示了如何创建一个最小的串行驱动程序。*  它不依赖于任何支持硬件,而是创建一个计时器来模拟从某种硬件接收的数据。*/#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/module.h>#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
#define DRIVER_DESC "Tiny serial 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_SERIAL_MAJOR  240 /* experimental range */
#define TINY_SERIAL_MINORS  1   /* only have one minor */
#define UART_NR         1   /* only use one port */#define TINY_SERIAL_NAME "ttytiny"#define MY_NAME          TINY_SERIAL_NAMEstatic struct timer_list *timer;static void tiny_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
}static void tiny_stop_rx(struct uart_port *port)
{
}static void tiny_enable_ms(struct uart_port *port)
{
}static void tiny_tx_chars(struct uart_port *port)
{struct circ_buf *xmit = &port->info->xmit;int count;if (port->x_char) {pr_debug("wrote %2x", port->x_char);port->icount.tx++;port->x_char = 0;return;}if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {tiny_stop_tx(port, 0);return;}count = port->fifosize >> 1;do {pr_debug("wrote %2x", xmit->buf[xmit->tail]);xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);port->icount.tx++;if (uart_circ_empty(xmit))break;} while (--count > 0);if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)uart_write_wakeup(port);if (uart_circ_empty(xmit))tiny_stop_tx(port, 0);
}static void tiny_start_tx(struct uart_port *port, unsigned int tty_start)
{
}static void tiny_timer(unsigned long data)
{struct uart_port *port;struct tty_struct *tty;port = (struct uart_port *)data;if (!port)return;if (!port->info)return;tty = port->info->tty;if (!tty)return;/* add one character 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_flip_buffer_push(tty);/* resubmit the timer again */timer->expires = jiffies + DELAY_TIME;add_timer(timer);/* see if we have any data to transmit */tiny_tx_chars(port);
}static unsigned int tiny_tx_empty(struct uart_port *port)
{return 0;
}static unsigned int tiny_get_mctrl(struct uart_port *port)
{return 0;
}static void tiny_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}static void tiny_break_ctl(struct uart_port *port, int break_state)
{
}static void tiny_set_termios(struct uart_port *port,struct termios *new, struct termios *old)
{int baud, quot, cflag = new->c_cflag;/* get the byte size */switch (cflag & CSIZE) {case CS5:printk(KERN_DEBUG " - data bits = 5\n");break;case CS6:printk(KERN_DEBUG " - data bits = 6\n");break;case CS7:printk(KERN_DEBUG " - data bits = 7\n");break;default: // CS8printk(KERN_DEBUG " - data bits = 8\n");break;}/* determine the parity */if (cflag & PARENB)if (cflag & PARODD)pr_debug(" - parity = odd\n");elsepr_debug(" - parity = even\n");elsepr_debug(" - parity = none\n");/* figure out the stop bits requested */if (cflag & CSTOPB)pr_debug(" - stop bits = 2\n");elsepr_debug(" - stop bits = 1\n");/* figure out the flow control settings */if (cflag & CRTSCTS)pr_debug(" - RTS/CTS is enabled\n");elsepr_debug(" - RTS/CTS is disabled\n");/* Set baud rate */baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);quot = uart_get_divisor(port, baud);//UART_PUT_DIV_LO(port, (quot & 0xff));//UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
}static int tiny_startup(struct uart_port *port)
{/* this is the first time this port is opened *//* do any hardware initialization needed here *//* create our timer and submit it */if (!timer) {timer = kmalloc(sizeof(*timer), GFP_KERNEL);if (!timer)return -ENOMEM;}timer->data = (unsigned long)port;timer->expires = jiffies + DELAY_TIME;timer->function = tiny_timer;add_timer(timer);return 0;
}static void tiny_shutdown(struct uart_port *port)
{/* The port is being closed by the last user. *//* Do any hardware specific stuff here *//* shut down our timer */del_timer(timer);
}static const char *tiny_type(struct uart_port *port)
{return "tinytty";
}static void tiny_release_port(struct uart_port *port)
{}static int tiny_request_port(struct uart_port *port)
{return 0;
}static void tiny_config_port(struct uart_port *port, int flags)
{
}static int tiny_verify_port(struct uart_port *port, struct serial_struct *ser)
{return 0;
}static struct uart_ops tiny_ops = {.tx_empty  = tiny_tx_empty,.set_mctrl = tiny_set_mctrl,.get_mctrl    = tiny_get_mctrl,.stop_tx  = tiny_stop_tx,.start_tx   = tiny_start_tx,.stop_rx   = tiny_stop_rx,.enable_ms  = tiny_enable_ms,.break_ctl    = tiny_break_ctl,.startup  = tiny_startup,.shutdown   = tiny_shutdown,.set_termios   = tiny_set_termios,.type       = tiny_type,.release_port  = tiny_release_port,.request_port  = tiny_request_port,.config_port   = tiny_config_port,.verify_port    = tiny_verify_port,
};static struct uart_port tiny_port = {.ops        = &tiny_ops,
};static struct uart_driver tiny_reg = {.owner     = THIS_MODULE,.driver_name = TINY_SERIAL_NAME,.dev_name   = TINY_SERIAL_NAME,.major      = TINY_SERIAL_MAJOR,.minor     = TINY_SERIAL_MINORS,.nr       = UART_NR,
};static int __init tiny_init(void)
{int result;printk(KERN_INFO "Tiny serial driver loaded\n");result = uart_register_driver(&tiny_reg);if (result)return result;result = uart_add_one_port(&tiny_reg, &tiny_port);if (result)uart_unregister_driver(&tiny_reg);return result;
}module_init(tiny_init);

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 <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <asm/uaccess.h>#define DRIVER_VERSION "v2.0"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
#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->flip.count >= TTY_FLIPBUF_SIZE)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;init_MUTEX(&tiny->sem);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;}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 termios *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 = 5\n");break;case CS6:printk(KERN_DEBUG " - data bits = 6\n");break;case CS7:printk(KERN_DEBUG " - data bits = 7\n");break;default:case CS8:printk(KERN_DEBUG " - data bits = 8\n");break;}/* determine the parity */if (cflag & PARENB)if (cflag & PARODD)printk(KERN_DEBUG " - parity = odd\n");elseprintk(KERN_DEBUG " - parity = even\n");elseprintk(KERN_DEBUG " - parity = none\n");/* figure out the stop bits requested */if (cflag & CSTOPB)printk(KERN_DEBUG " - stop bits = 2\n");elseprintk(KERN_DEBUG " - stop bits = 1\n");/* figure out the hardware flow control settings */if (cflag & CRTSCTS)printk(KERN_DEBUG " - RTS/CTS is enabled\n");elseprintk(KERN_DEBUG " - RTS/CTS is disabled\n");/* determine software flow control *//* if we are implementing XON/XOFF, set the start and * stop character in the device */if (I_IXOFF(tty) || I_IXON(tty)) {unsigned char stop_char  = STOP_CHAR(tty);unsigned char start_char = START_CHAR(tty);/* if we are implementing INBOUND XON/XOFF */if (I_IXOFF(tty))printk(KERN_DEBUG " - INBOUND XON/XOFF is enabled, ""XON = %2x, XOFF = %2x", start_char, stop_char);elseprintk(KERN_DEBUG" - INBOUND XON/XOFF is disabled");/* if we are implementing OUTBOUND XON/XOFF */if (I_IXON(tty))printk(KERN_DEBUG" - OUTBOUND XON/XOFF is enabled, ""XON = %2x, XOFF = %2x", start_char, stop_char);elseprintk(KERN_DEBUG" - OUTBOUND XON/XOFF is disabled");}/* get the baud rate wanted */printk(KERN_DEBUG " - baud rate = %d", tty_get_baud_rate(tty));
}/* Our fake UART values */
#define MCR_DTR     0x01
#define MCR_RTS     0x02
#define MCR_LOOP    0x04
#define MSR_CTS     0x08
#define MSR_CD      0x10
#define MSR_RI      0x20
#define MSR_DSR     0x40static int tiny_tiocmget(struct tty_struct *tty, struct file *file)
{struct tiny_serial *tiny = tty->driver_data;unsigned int result = 0;unsigned int msr = tiny->msr;unsigned int mcr = tiny->mcr;result = ((mcr & MCR_DTR)  ? TIOCM_DTR  : 0) | /* DTR is set */((mcr & MCR_RTS)  ? TIOCM_RTS  : 0) |   /* RTS is set */((mcr & MCR_LOOP) ? TIOCM_LOOP : 0) |   /* LOOP is set */((msr & MSR_CTS)  ? TIOCM_CTS  : 0) |  /* CTS is set */((msr & MSR_CD)   ? TIOCM_CAR  : 0) |   /* Carrier detect is set*/((msr & MSR_RI)   ? TIOCM_RI   : 0) | /* Ring Indicator is set */((msr & MSR_DSR)  ? TIOCM_DSR  : 0); /* DSR is set */return result;
}static int tiny_tiocmset(struct tty_struct *tty, struct file *file,unsigned int set, unsigned int clear)
{struct tiny_serial *tiny = tty->driver_data;unsigned int mcr = tiny->mcr;if (set & TIOCM_RTS)mcr |= MCR_RTS;if (set & TIOCM_DTR)mcr |= MCR_RTS;if (clear & TIOCM_RTS)mcr &= ~MCR_RTS;if (clear & TIOCM_DTR)mcr &= ~MCR_RTS;/* set the new MCR value in the device */tiny->mcr = mcr;return 0;
}static int tiny_read_proc(char *page, char **start, off_t off, int count,int *eof, void *data)
{struct tiny_serial *tiny;off_t begin = 0;int length = 0;int i;length += sprintf(page, "tinyserinfo:1.0 driver:%s\n", DRIVER_VERSION);for (i = 0; i < TINY_TTY_MINORS && length < PAGE_SIZE; ++i) {tiny = tiny_table[i];if (tiny == NULL)continue;length += sprintf(page+length, "%d\n", i);if ((length + begin) > (off + count))goto done;if ((length + begin) < off) {begin += length;length = 0;}}*eof = 1;
done:if (off >= (length + begin))return 0;*start = page + (off-begin);return (count < begin+length-off) ? count : begin + length-off;
}#define tiny_ioctl tiny_ioctl_tiocgserial
static int tiny_ioctl(struct tty_struct *tty, struct file *file,unsigned int cmd, unsigned long arg)
{struct tiny_serial *tiny = tty->driver_data;if (cmd == TIOCGSERIAL) {struct serial_struct tmp;if (!arg)return -EFAULT;memset(&tmp, 0, sizeof(tmp));tmp.type      = tiny->serial.type;tmp.line        = tiny->serial.line;tmp.port        = tiny->serial.port;tmp.irq         = tiny->serial.irq;tmp.flags        = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;tmp.xmit_fifo_size  = tiny->serial.xmit_fifo_size;tmp.baud_base     = tiny->serial.baud_base;tmp.close_delay        = 5*HZ;tmp.closing_wait    = 30*HZ;tmp.custom_divisor = tiny->serial.custom_divisor;tmp.hub6      = tiny->serial.hub6;tmp.io_type     = tiny->serial.io_type;if (copy_to_user((void __user *)arg, &tmp, sizeof(struct serial_struct)))return -EFAULT;return 0;}return -ENOIOCTLCMD;
}
#undef tiny_ioctl#define tiny_ioctl tiny_ioctl_tiocmiwait
static int tiny_ioctl(struct tty_struct *tty, struct file *file,unsigned int cmd, unsigned long arg)
{struct tiny_serial *tiny = tty->driver_data;if (cmd == TIOCMIWAIT) {DECLARE_WAITQUEUE(wait, current);struct async_icount cnow;struct async_icount cprev;cprev = tiny->icount;while (1) {add_wait_queue(&tiny->wait, &wait);set_current_state(TASK_INTERRUPTIBLE);schedule();remove_wait_queue(&tiny->wait, &wait);/* see if a signal woke us up */if (signal_pending(current))return -ERESTARTSYS;cnow = tiny->icount;if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)return -EIO; /* no change => error */if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) ||((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {return 0;}cprev = cnow;}}return -ENOIOCTLCMD;
}
#undef tiny_ioctl#define tiny_ioctl tiny_ioctl_tiocgicount
static int tiny_ioctl(struct tty_struct *tty, struct file *file,unsigned int cmd, unsigned long arg)
{struct tiny_serial *tiny = tty->driver_data;if (cmd == TIOCGICOUNT) {struct async_icount cnow = tiny->icount;struct serial_icounter_struct icount;icount.cts = cnow.cts;icount.dsr  = cnow.dsr;icount.rng  = cnow.rng;icount.dcd  = cnow.dcd;icount.rx   = cnow.rx;icount.tx    = cnow.tx;icount.frame = cnow.frame;icount.overrun    = cnow.overrun;icount.parity   = cnow.parity;icount.brk   = cnow.brk;icount.buf_overrun = cnow.buf_overrun;if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))return -EFAULT;return 0;}return -ENOIOCTLCMD;
}
#undef tiny_ioctl/* the real tiny_ioctl function.  The above is done to get the small functions in the book */
static int tiny_ioctl(struct tty_struct *tty, struct file *file,unsigned int cmd, unsigned long arg)
{switch (cmd) {case TIOCGSERIAL:return tiny_ioctl_tiocgserial(tty, file, cmd, arg);case TIOCMIWAIT:return tiny_ioctl_tiocmiwait(tty, file, cmd, arg);case TIOCGICOUNT:return tiny_ioctl_tiocgicount(tty, file, cmd, arg);}return -ENOIOCTLCMD;
}static struct tty_operations serial_ops = {.open = tiny_open,.close = tiny_close,.write = tiny_write,.write_room = tiny_write_room,.set_termios = tiny_set_termios,
};static struct tty_driver *tiny_tty_driver;static int __init tiny_init(void)
{int retval;int i;/* allocate the tty driver */tiny_tty_driver = alloc_tty_driver(TINY_TTY_MINORS);if (!tiny_tty_driver)return -ENOMEM;/* initialize the tty driver */tiny_tty_driver->owner = THIS_MODULE;tiny_tty_driver->driver_name = "tiny_tty";tiny_tty_driver->name = "ttty";tiny_tty_driver->devfs_name = "tts/ttty%d";tiny_tty_driver->major = TINY_TTY_MAJOR,tiny_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,tiny_tty_driver->subtype = SERIAL_TYPE_NORMAL,tiny_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,tiny_tty_driver->init_termios = tty_std_termios;tiny_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;tty_set_operations(tiny_tty_driver, &serial_ops);/* hack to make the book purty, yet still use these functions in the* real driver.  They really should be set up in the serial_ops* structure above... */tiny_tty_driver->read_proc = tiny_read_proc;tiny_tty_driver->tiocmget = tiny_tiocmget;tiny_tty_driver->tiocmset = tiny_tiocmset;tiny_tty_driver->ioctl = tiny_ioctl;/* register the tty driver */retval = tty_register_driver(tiny_tty_driver);if (retval) {printk(KERN_ERR "failed to register tiny tty driver");put_tty_driver(tiny_tty_driver);return retval;}for (i = 0; i < TINY_TTY_MINORS; ++i)tty_register_device(tiny_tty_driver, i, NULL);printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION);return retval;
}static void __exit tiny_exit(void)
{struct tiny_serial *tiny;int i;for (i = 0; i < TINY_TTY_MINORS; ++i)tty_unregister_device(tiny_tty_driver, 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);

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
elseDEBFLAGS = -O2
endifCFLAGS += $(DEBFLAGS)
CFLAGS += -I..ifneq ($(KERNELRELEASE),)
# call from kernel build systemobj-m    := tiny_tty.o tiny_serial.oelseKERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD       := $(shell pwd)default:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesendifclean:rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versionsdepend .depend dep:$(CC) $(CFLAGS) -M *.c > .dependifeq (.depend,$(wildcard .depend))
include .depend
endif

如何创建一个最小的串口、TTY设备包括虚拟控制台,串口以及伪终端设备的驱动程序相关推荐

  1. 基类和派生类写在一个文件中_BootISO:从 ISO 文件中创建一个可启动的 USB 设备...

    今天,我们将讨论名为 BootISO 的实用程序类似工具.它是一个简单的 bash 脚本,允许用户来从 ISO 文件中创建一个可启动的 USB 设备. -- Prakash Subramanian(作 ...

  2. BootISO:从 ISO 文件中创建一个可启动的 USB 设备

    为了安装操作系统,我们中的大多数人(包括我)经常从 ISO 文件中创建一个可启动的 USB 设备.为达到这个目的,在 Linux 中有很多自由可用的应用程序.甚至在过去我们写了几篇介绍这种实用程序的文 ...

  3. dd命令iso linux_BootISO:从 ISO 文件中创建一个可启动的 USB 设备

    今天,我们将讨论名为 BootISO 的实用程序类似工具.它是一个简单的 bash 脚本,允许用户来从 ISO 文件中创建一个可启动的 USB 设备. -- Prakash Subramanian(作 ...

  4. Android 通过串口获取设备号 android串口测试工具 完整解析

    前言 android 工业平板RK3399-all 调试有关串口的设备 如何获取对应的串口设备及串口名字 先来一张图说明 获取串口 SerialPortFinder mSerialPortFinder ...

  5. 【创建包:employee,完成如下功能】1. 创建一个员工类(Employee),其中包括:1) 4个私有属性:员工姓名(name)、员工年龄(age)、员工职位(position)、工资

    [创建包:employee,完成如下功能] 1. 创建一个员工类(Employee),其中包括: 1) 4个私有属性:员工姓名(name).员工年龄(age).员工职位(position).工资(sa ...

  6. 如何创建一个最小的区块链

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 这是我在一个外文网站上看到的一篇博文,作者通过50行代码写出了区块链的简化版本.麻雀虽小,但是五脏俱全.我觉得通过实践, ...

  7. 创建一个最小的D3D11实例

    我想复习一下D3D11的一些基础API,于是翻了翻Microsoft DirectX SDK (June 2010)找到其中一个最简单的D3D11的实例(\Samples\C++\Direct3D11 ...

  8. linux tty设备驱动,18.1. 一个小 TTY 驱动

    ## 18.1. 一个小 TTY 驱动 为解释 tty 核心如何工作, 我们创建一个小 tty 驱动, 可以被加载, 以及写入读出, 并且卸载. 任何一个 tty 驱动的主要数据结构是 struct ...

  9. linux设备驱动之串口移植,Linux设备驱动之UART驱动结构

    一.对于串口驱动Linux系统中UART驱动属于终端设备驱动,应该说是实现串口驱动和终端驱动来实现串口终端设备的驱动.要了解串口终端的驱动在Linux系统的结构就先要了解终端设备驱动在Linux系统中 ...

最新文章

  1. #mysql50#_#mysql50#.ssh设个啥数据库?
  2. POJ-2391 Ombrophobic Bovines 网络流-拆点构图
  3. dedecms怎么改php版本_Linux下如何安装DedeCMS?
  4. Java socket调用Http协议Get请求
  5. Python自动化之高级语法单例模式
  6. ES2021 更新的内容!
  7. Better Explained 以通俗易懂的语言阐释数学
  8. CDN技术--分布式网站架构必备利器
  9. 如何解决 zsh: event not found: e]st1问题
  10. 开发游戏十年,遭遇游戏开发史上最诡异事件,然而被我成功解决了!
  11. 2020-8-15 无线充电原理和注意事项 WCP/铁氧体
  12. Flink学习笔记【巨详细!】(二)
  13. 红外线 电磁波频谱
  14. java 霍思_心术结局是什么
  15. 大宗物资采购和运销-煤炭/钢铁/物流数据资源
  16. 数据库和HTML的使用
  17. OpenMV入门(下)
  18. 带你飞过PMP—备考上篇•乖乖看书就对了-GZ1610吴慧敏
  19. 用jquery根据json动态创建多级菜单导航(by https://www.cnblogs.com/fatty-yu/p/7088955.html)...
  20. vue实现仿DJI大疆官网顶部导航栏组件

热门文章

  1. 从Centos7升级到Centos8的教程(图文详解)
  2. Java基础-序列化和反序列化
  3. 搭建了Pycharm对话平台
  4. Angular问题02 创建模块失败、 angular-cli名称问题、升级angular-cli
  5. 刷题总结——road(ssoi)
  6. POJ3264Balanced Lineup(最基础的线段树)
  7. cocos2dx遇到的坑1
  8. canvas中window坐标转换为canvas坐标
  9. shell脚本之从1加到100之和的思路
  10. android支付宝余额怎么做,android实现类似于支付宝余额快速闪动的效果 -电脑资料...