Linux串口驱动源码
时间: 2023-10-18 10:12:15 浏览: 159
Linux serial构架分析及驱动开发
5星 · 资源好评率100%
下面是一个简单的Linux串口驱动程序的源代码,仅用于参考:
```c
#include <linux/module.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#define DRIVER_NAME "my_serial"
#define MY_MAJOR 200
#define MY_MINOR 0
#define MY_DEV_COUNT 2
#define MY_BUFFER_SIZE 256
static struct cdev my_cdev;
static struct tty_driver *my_tty_driver;
static struct tty_port my_tty_port;
static char *my_buffer;
static int my_buffer_index = 0;
static struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = my_open,
.release = my_release,
.read = my_read,
.write = my_write,
.llseek = no_llseek,
};
static int my_open(struct inode *inode, struct file *file)
{
tty_port_open(&my_tty_port, file);
return 0;
}
static int my_release(struct inode *inode, struct file *file)
{
tty_port_close(&my_tty_port, file);
return 0;
}
static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
int read_count = 0;
if (my_buffer_index > 0) {
read_count = my_buffer_index;
if (read_count > count) {
read_count = count;
}
if (copy_to_user(buf, my_buffer, read_count)) {
read_count = -EFAULT;
} else {
my_buffer_index = 0;
}
}
return read_count;
}
static ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
int write_count = 0;
if (count > MY_BUFFER_SIZE) {
count = MY_BUFFER_SIZE;
}
write_count = tty_write_room(&my_tty_port);
if (write_count > count) {
write_count = count;
}
if (copy_from_user(my_buffer, buf, write_count)) {
write_count = -EFAULT;
} else {
my_buffer_index = write_count;
tty_port_tty_wakeup(&my_tty_port);
}
return write_count;
}
static int my_tty_install(struct tty_driver *driver, struct tty_struct *tty)
{
tty_port_init(&my_tty_port);
my_tty_port.ops = &my_tty_port_ops;
my_tty_port.tty = tty;
tty->driver_data = &my_tty_port;
return tty_port_install(&my_tty_port, driver, tty);
}
static void my_tty_remove(struct tty_driver *driver, struct tty_struct *tty)
{
tty_port_destroy(&my_tty_port);
}
static const struct tty_port_operations my_tty_port_ops = {
.write = my_tty_write,
.flush_buffer = my_tty_flush_buffer,
.tiocmget = my_tty_tiocmget,
.tiocmset = my_tty_tiocmset,
};
static int my_tty_write(struct tty_port *port, const char *buf, int count)
{
int write_count = 0;
if (my_buffer_index == 0) {
write_count = tty_write_room(port);
if (write_count > count) {
write_count = count;
}
if (copy_from_user(my_buffer, buf, write_count)) {
write_count = -EFAULT;
} else {
my_buffer_index = write_count;
wake_up_interruptible(&port->write_wait);
}
}
return write_count;
}
static void my_tty_flush_buffer(struct tty_port *port)
{
my_buffer_index = 0;
}
static int my_tty_tiocmget(struct tty_port *port)
{
return 0;
}
static int my_tty_tiocmset(struct tty_port *port, unsigned int set, unsigned int clear)
{
return 0;
}
static int __init my_serial_init(void)
{
int result = 0;
dev_t devno = MKDEV(MY_MAJOR, MY_MINOR);
result = register_chrdev_region(devno, MY_DEV_COUNT, DRIVER_NAME);
if (result < 0) {
printk(KERN_WARNING "Failed to register device number %d, error %d\n", MY_MAJOR, result);
goto failed_register_region;
}
cdev_init(&my_cdev, &my_fops);
my_cdev.owner = THIS_MODULE;
result = cdev_add(&my_cdev, devno, MY_DEV_COUNT);
if (result < 0) {
printk(KERN_WARNING "Failed to add cdev, error %d\n", result);
goto failed_add_cdev;
}
my_tty_driver = alloc_tty_driver(MY_DEV_COUNT);
if (!my_tty_driver) {
printk(KERN_WARNING "Failed to allocate tty driver\n");
goto failed_alloc_tty_driver;
}
my_tty_driver->driver_name = DRIVER_NAME;
my_tty_driver->name = "ttyMY";
my_tty_driver->install = my_tty_install;
my_tty_driver->remove = my_tty_remove;
tty_set_operations(my_tty_driver, &my_tty_ops);
result = tty_register_driver(my_tty_driver);
if (result < 0) {
printk(KERN_WARNING "Failed to register tty driver, error %d\n", result);
goto failed_register_tty_driver;
}
my_buffer = kmalloc(MY_BUFFER_SIZE, GFP_KERNEL);
if (!my_buffer) {
printk(KERN_WARNING "Failed to allocate buffer\n");
result = -ENOMEM;
goto failed_alloc_buffer;
}
return 0;
failed_alloc_buffer:
tty_unregister_driver(my_tty_driver);
failed_register_tty_driver:
put_tty_driver(my_tty_driver);
failed_alloc_tty_driver:
cdev_del(&my_cdev);
failed_add_cdev:
unregister_chrdev_region(devno, MY_DEV_COUNT);
failed_register_region:
return result;
}
static void __exit my_serial_exit(void)
{
kfree(my_buffer);
tty_unregister_driver(my_tty_driver);
put_tty_driver(my_tty_driver);
cdev_del(&my_cdev);
unregister_chrdev_region(MKDEV(MY_MAJOR, MY_MINOR), MY_DEV_COUNT);
}
module_init(my_serial_init);
module_exit(my_serial_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("My Serial Driver");
```
这个驱动程序实现了一个简单的串口设备,它包括:
1. 定义了设备驱动程序的名称和设备号。
2. 实现了设备文件的 open、release、read 和 write 操作。
3. 定义了 tty_port 和 tty_driver 结构体以及它们的操作函数。
4. 实现了 tty_driver 的 install 和 remove 操作。
5. 注册了设备驱动程序,tty_driver 和 tty_port,以及字符设备。
阅读全文