Linux内核编程小妙招

延时处理

#include <linux/device.h>
#include <linux/input.h>
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/workqueue.h>

struct work_poller {
	void (*poll)(void *dev);
	unsigned int poll_interval;
	void *private;
	struct delayed_work work;
};

void poller_queue_work(struct work_poller *poller)
{
	unsigned long delay;

	delay = msecs_to_jiffies(poller->poll_interval);
	if (delay >= HZ)
		delay = round_jiffies_relative(delay);

	queue_delayed_work(system_freezable_wq, &poller->work, delay);
}

void poller_work(struct work_struct *work)
{
	struct work_poller *poller = container_of(work, struct work_poller, work.work);

	poller->poll(poller->private);
	poller_queue_work(poller);
}

int init_polling(struct work_poller *polling, void (*poll_fn)(void *dev))
{
	polling = kzalloc(sizeof(struct work_poller), GFP_KERNEL);
	if (!polling) {
		dev_err(dev->dev.parent ?: &dev->dev, "%s: unable to allocate poller structure\n", __func__);
		return -ENOMEM;
	}
	INIT_DELAYED_WORK(&polling->work, poller_work);
	polling->poll = poll_fn;
	polling->private = 0;
	return 0;
}
//内核5.15
/*
struct delayed_work work;
INIT_DELAYED_WORK(&work, delay_work_fn);
void delay_work_fn(struct work_struct *work)
{
	{
	TODO ...
	}
	queue_delayed_work(system_freezable_wq, &work, delay_time);
}
*/

定时器

//内核5.15
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
#include <linux/time64.h>
#include <linux/timekeeping.h>
//static DEFINE_TIMER(timer, timer_handler);
struct timer_list *timer;
void timer_cb(struct timer_list *timer)
{
	TODO ...
	mod_timer(timer, jiffies + msecs_to_jiffies(1000));
}

void timer_init(void)
{
	timer_setup(&timer, timer_cb, 0);
	mod_timer(&tm, jiffies + msecs_to_jiffies(1000));
}

/proc文件系统

#include <linux/init.h>
#include <linux/types.h>
#include <linux/idr.h>
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/random.h>
#include <linux/major.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/poll.h>
#include <linux/device.h>
#include <linux/mutex.h>

static LIST_HEAD(dev_list);
static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
{
	//seq->private;
	TODO
	return seq_list_start(&dev_list, *pos);
}

static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
	TODO
	return seq_list_next(v, &dev_list, pos);
}

static void input_seq_stop(struct seq_file *seq, void *v)
{
	//seq->private;
	TODO
}

static int input_devices_seq_show(struct seq_file *seq, void *v)
{
	TODO
	return 0;
}
/*
struct seq_operations {
	void * (*start) (struct seq_file *m, loff_t *pos);
	void (*stop) (struct seq_file *m, void *v);
	void * (*next) (struct seq_file *m, void *v, loff_t *pos);
	int (*show) (struct seq_file *m, void *v);
};
*/
struct seq_operations devices_seq_ops = {
	.start	= input_devices_seq_start,
	.next	= input_devices_seq_next,
	.stop	= input_seq_stop,
	.show	= input_devices_seq_show,
};

int proc_devices_open(struct inode *inode, struct file *file)
{
	TODO
	seq_open(file, &devices_seq_ops);
	return 0;
}

struct proc_ops devices_proc_ops = {
	.proc_open	= proc_devices_open,
	.proc_read	= seq_read,
	.proc_lseek	= seq_lseek,
	.proc_release	= seq_release,
};

int __init input_proc_init(void)
{
	struct proc_dir_entry *entry;
	struct proc_dir_entry *proc_bus_dir;
	proc_bus_dir = proc_mkdir("bus/input", NULL);
	if (!proc_bus_input_dir)
		return -ENOMEM;
	entry = proc_create("devices", 0, proc_bus_dir, &devices_proc_ops);
	if (!entry)
		goto fail1;

	return 0;
 fail1: remove_proc_entry("bus/input", NULL);
	return -ENOMEM;
}

void input_proc_exit(void)
{
	remove_proc_entry("devices", proc_bus_input_dir);
	remove_proc_entry("bus/input", NULL);
}

/sys文件系统

struct bus_type bus_type = {
	.name = "name",
};

struct class class_type= {
	.name		= "className",
};
void sys_init(void)
{
	//在/sys/bus下创建目录
	bus_register(&bus_type);
	//在/sys/class下创建目录
	class_register(&class_type);
}

void sys_exit(void)
{
	bus_unregister(&bus_type);
}

DEBUG_FS

static ssize_t iio_debugfs_read_reg(struct file *file, char __user *userbuf, size_t count, loff_t *ppos)
{
	//file->private_data;
	TODO
	//ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos, const void *from, size_t available);
	return simple_read_from_buffer(userbuf, count, ppos, buffer, size);
}

static ssize_t iio_debugfs_write_reg(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos)
{
	//file->private_data;
	//copy_from_user(buf, userbuf, count)
	//sscanf(buf, "%i %i", &reg, &val)
	TODO
	return count;
}

static const struct file_operations debugfs_fops = {
	.open = simple_open,
	.read = iio_debugfs_read_reg,
	.write = iio_debugfs_write_reg,
};

void debug_init(void)
{
	struct dentry *debugfs_dentry
	debugfs_dentry = debugfs_create_dir("iio", NULL);
	//struct dentry *debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, void *data, const struct file_operations *fops);
	debugfs_create_file("direct_reg_access", 0644, debugfs_dentry , &private_data, &debugfs_fops);
}
void debug_exit(void)
{
	debugfs_remove(debugfs_dentry);
}

irq_domain

/*
static const struct of_device_id irqchip_of_match_end __used __section("__irqchip_of_table_end");

extern struct of_device_id __irqchip_of_table[];

void __init irqchip_init(void)
{
	of_irq_init(__irqchip_of_table);
	acpi_probe_device_table(irqchip);
}

int platform_irqchip_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct device_node *par_np = of_irq_find_parent(np);
	of_irq_init_cb_t irq_init_cb = of_device_get_match_data(&pdev->dev);

	if (!irq_init_cb)
		return -EINVAL;

	if (par_np == np)
		par_np = NULL;
	if (par_np && !irq_find_matching_host(par_np, DOMAIN_BUS_ANY))
		return -EPROBE_DEFER;

	return irq_init_cb(np, par_np);
}
EXPORT_SYMBOL_GPL(platform_irqchip_probe);

#define IRQCHIP_PLATFORM_DRIVER_BEGIN(drv_name) \
static const struct of_device_id drv_name##_irqchip_match_table[] = {

#define IRQCHIP_MATCH(compat, fn) { .compatible = compat, .data = fn },

#define IRQCHIP_PLATFORM_DRIVER_END(drv_name)				\
	{},								\
};									\
MODULE_DEVICE_TABLE(of, drv_name##_irqchip_match_table);		\
static struct platform_driver drv_name##_driver = {		\
	.probe  = platform_irqchip_probe,				\
	.driver = {							\
		.name = #drv_name,					\
		.owner = THIS_MODULE,					\
		.of_match_table = drv_name##_irqchip_match_table,	\
		.suppress_bind_attrs = true,				\
	},								\
};									\
builtin_platform_driver(drv_name##_driver)
*/

IRQCHIP_PLATFORM_DRIVER_BEGIN(drv_name)
IRQCHIP_MATCH(compat, fn)
IRQCHIP_PLATFORM_DRIVER_END(drv_name)
//或者
MODULE_DEVICE_TABLE(of, drv_name);
builtin_platform_driver(drv_name);

irq

struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
	[0 ... NR_IRQS-1] = {
		.handle_irq	= handle_bad_irq,
		.depth		= 1,
		.lock		= __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
	}
};

int __init early_irq_init(void)
{
	int count, i, node = first_online_node;
	struct irq_desc *desc;

	init_irq_default_affinity();

	printk(KERN_INFO "NR_IRQS: %d\n", NR_IRQS);

	desc = irq_desc;
	count = ARRAY_SIZE(irq_desc);

	for (i = 0; i < count; i++) {
		desc[i].kstat_irqs = alloc_percpu(unsigned int);
		alloc_masks(&desc[i], node);
		raw_spin_lock_init(&desc[i].lock);
		lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
		mutex_init(&desc[i].request_mutex);
		init_waitqueue_head(&desc[i].wait_for_threads);
		desc_set_defaults(i, &desc[i], node, NULL, NULL);
	}
	//对应与不同架构,如arch/ia64/kernel/irq.c
	return arch_early_irq_init();
}

bootargs传递以及处理

struct obs_kernel_param {
	const char *str;
	int (*setup_func)(char *);
	int early;
};
/*
 * Only for really core code.  See moduleparam.h for the normal way.
 * Force the alignment so the compiler doesn't space elements of the
 * obs_kernel_param "array" too far apart in .init.setup.
 */
#define __setup_param(str, unique_id, fn, early)			\
	static const char __setup_str_##unique_id[] __initconst		\
		__aligned(1) = str; 					\
	static struct obs_kernel_param __setup_##unique_id		\
		__used __section(".init.setup")				\
		__aligned(__alignof__(struct obs_kernel_param))		\
		= { __setup_str_##unique_id, fn, early }

#define __setup(str, fn)						\
	__setup_param(str, fn, fn, 0)
//一般用于bootargs传递参数
/*
如:__setup("irqaffinity=", irq_affinity_setup);对应的设备树
chosen: chosen {
		bootargs = "console=ttyMSM0,115200n8 ... irqaffinity=0-3 ...";
};
*/

工作队列

/*
include/linux/workqueue.h
*/
struct work_struct {
	atomic_long_t data;
	struct list_head entry;
	work_func_t func;
#ifdef CONFIG_LOCKDEP
	struct lockdep_map lockdep_map;
#endif
	ANDROID_KABI_RESERVE(1);
	ANDROID_KABI_RESERVE(2);
};

#define WORK_DATA_INIT()	ATOMIC_LONG_INIT((unsigned long)WORK_STRUCT_NO_POOL)
#define WORK_DATA_STATIC_INIT()	\
	ATOMIC_LONG_INIT((unsigned long)(WORK_STRUCT_NO_POOL | WORK_STRUCT_STATIC))

struct delayed_work {
	struct work_struct work;
	struct timer_list timer;

	/* target workqueue and CPU ->timer uses to queue ->work */
	struct workqueue_struct *wq;
	int cpu;

	ANDROID_KABI_RESERVE(1);
	ANDROID_KABI_RESERVE(2);
};
/**
 * schedule_work - put work task in global workqueue
 * @work: job to be done
 */
static inline bool schedule_work(struct work_struct *work)
{
	return queue_work(system_wq, work);
}

#define __INIT_WORK(_work, _func, _onstack)				\
	do {								\
		__init_work((_work), _onstack);				\
		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
		INIT_LIST_HEAD(&(_work)->entry);			\
		(_work)->func = (_func);				\
	} while (0)
#endif

#define INIT_WORK(_work, _func)						\
	__INIT_WORK((_work), (_func), 0)

python3在windows上的串口测试代码

import threading
from time import *
import re
import serial
import serial.tools.list_ports

#扫描串口
def serial_scanf():
    port_list = list(serial.tools.list_ports.comports())
    if len(port_list) == 0:
        print('无可用串口')
    else:
        for i in range(0,len(port_list)):
            print(port_list[i])

#打开串口
def serial_open(port, bps):
    global ser
    try:
        ser = serial.Serial(port, bps, stopbits=1, bytesize=8, timeout=0.01)
        return ser
    except Exception as result:
        print("Open serial {} failed".format(port))
        sleep(1)
        print(result)
        return False

#关闭串口
def serial_close():
    ser.close()

#发送数据
def serial_send(buf):
    len = ser.write(buf.encode('utf-8'))
    len += ser.write("\r\n".encode('utf-8'))
    return len

#接收数据
def serial_recv(expect = "OK", timeout = 6):
    response=''
    start_time = time()
    while 1:
        data = ser.readline()
        if data != b'':
            response += data.decode('utf-8')
        if re.findall("OK",data.decode('utf-8')) or time() - start_time > timeout :
                break
    print(response)
    if expect == "":
        return response
    if re.findall(expect,response):
        return True
    else:
        return False
if __name__ == "__main__":
    serial_scanf()
    serial_open("COM28", 115200)
    serial_send("AT")
    str = serial_recv()
    print(str)