1. 程式人生 > >《5.linux驅動開發-第6部分-5.6.misc類裝置與蜂鳴器驅動》

《5.linux驅動開發-第6部分-5.6.misc類裝置與蜂鳴器驅動》

《5.linux驅動開發-第6部分-5.6.misc類裝置與蜂鳴器驅動》

第一部分、章節目錄
5.6.1.板載蜂鳴器驅動測試
5.6.2.misc類裝置介紹
5.6.3.misc驅動框架原始碼分析1
5.6.4.misc驅動框架原始碼分析2
5.6.5.蜂鳴器驅動原始碼分析1
5.6.6.蜂鳴器驅動原始碼分析2

第二部分、章節介紹
5.6.1.板載蜂鳴器驅動測試
本節使用核心中提供的蜂鳴器驅動來實踐測試蜂鳴器,要同時解決驅動層的問題和應用程式的編寫。
5.6.2.misc類裝置介紹
本節系統介紹misc類裝置的概念和分類特點,並且對misc類裝置的驅動框架詳細講解。
5.6.3.misc驅動框架原始碼分析1
本節分析misc類裝置驅動框架中核心自己實現的部分,即misc.c。
5.6.4.misc驅動框架原始碼分析2
本節繼續分析misc.c,重點是訊號量及其使用的一般技巧。
5.6.5.蜂鳴器驅動原始碼分析1
本節分析九鼎提供的buzzer驅動原始碼
5.6.6.蜂鳴器驅動原始碼分析2
本節分析九鼎提供的buzzer驅動原始碼

第三部分、隨堂記錄
5.6.1.板載蜂鳴器驅動測試
5.6.1.1、驅動部分
(1)九鼎移植核心已經提供了蜂鳴器驅動原始碼
(2)make menuconfig
(3)bug排查。修改Makefile中的巨集名,最終可以在系統中看到 /dev/buzzer
5.6.1.2、應用部分
(1)應用編寫:開啟檔案+ioctl
(2)測試實踐

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>


#define DEVNAME		"/dev/buzzer"

#define PWM_IOCTL_SET_FREQ		1
#define PWM_IOCTL_STOP 0 int main(void) { int fd = -1; fd = open(DEVNAME, O_RDWR); if (fd < 0) { perror("open"); return -1; } ioctl(fd, PWM_IOCTL_SET_FREQ, 10000); sleep(3); ioctl(fd, PWM_IOCTL_STOP); sleep(3); ioctl(fd, PWM_IOCTL_SET_FREQ, 3000); sleep(3); ioctl(fd, PWM_IOCTL_STOP)
; sleep(3); close(fd); return 0; }

5.6.2.misc類裝置介紹
5.6.2.1、何為misc
(1)中文名:雜項裝置\雜散裝置
(2)/sys/class/misc
(3)典型的字元裝置
(4)有一套驅動框架,核心實現一部分(misc.c),驅動實現一部分(x210-buzzer.c)。
(5)misc是對原始的字元設備註冊介面的一個類層次的封裝,很多典型字元裝置都可以歸類到misc類中,使用misc驅動框架來管理。
5.6.2.2、misc類裝置驅動架構
(1)核心開發者實現部分,關鍵點有2個:一個是類的建立,另一個是開放給驅動開發者的介面
(2)具體裝置驅動工程師實現部分
5.6.2.3、本部分學習方法
(1)蜂鳴器驅動原始碼已有,分析為主
(2)複習並驗證前面講的驅動框架的思維
(3)有餘力的不妨開始注意一些細節

5.6.3.misc驅動框架原始碼分析1
5.6.3.1、misc原始碼框架基礎
(1)misc原始碼框架本身也是一個模組,核心啟動時自動載入
(2)原始碼框架的主要工作:註冊misc類,使用老介面註冊字元裝置驅動(主裝置號10),開放device註冊的介面misc_register給驅動工程師
5.6.3.2、misc類裝置的註冊
(1)驅動工程師需要藉助misc來載入自己的驅動時,只需要呼叫misc_register介面註冊自己的裝置即可,其餘均不用管。
(2)misc_list連結串列的作用。核心定義了一個misc_list連結串列用來記錄所有核心中註冊了的雜散類裝置。當我們向核心註冊一個misc類裝置時,核心就會向misc_list連結串列中insert一個節點。
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name)
struct list_head name = LIST_HEAD_INIT(name)

原式子:static LIST_HEAD(misc_list);
展開後:static struct list_head misc_list = { &(misc_list), &(misc_list) }
(3)主裝置號和次裝置號的作用和區分

/*
 * linux/drivers/char/misc.c
 *
 * Generic misc open routine by Johan Myreen
 *
 * Based on code from Linus
 *
 * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's
 *   changes incorporated into 0.97pl4
 *   by Peter Cervasio (pete%[email protected]) (08SEP92)
 *   See busmouse.c for particulars.
 *
 * Made things a lot mode modular - easy to compile in just one or two
 * of the misc drivers, as they are now completely independent. Linus.
 *
 * Support for loadable modules. 8-Sep-95 Philip Blundell <[email protected]>
 *
 * Fixed a failing symbol register to free the device registration
 *		Alan Cox <[email protected]> 21-Jan-96
 *
 * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96
 *
 * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96
 *
 * Handling of mouse minor numbers for kerneld:
 *  Idea by Jacques Gelinas <[email protected]>,
 *  adapted by Bjorn Ekwall <[email protected]>
 *  corrected by Alan Cox <[email protected]>
 *
 * Changes for kmod (from kerneld):
 *	Cyrus Durgin <[email protected]>
 *
 * Added devfs support. Richard Gooch <[email protected]>  10-Jan-1998
 */

#include <linux/module.h>

#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>

/*
 * Head entry for the doubly linked miscdevice list
 */
static LIST_HEAD(misc_list);
static DEFINE_MUTEX(misc_mtx);

/*
 * Assigned numbers, used for dynamic minors
 */
#define DYNAMIC_MINORS 64 /* like dynamic majors */
static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);

#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
{
	mutex_lock(&misc_mtx);
	return seq_list_start(&misc_list, *pos);
}

static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
	return seq_list_next(v, &misc_list, pos);
}

static void misc_seq_stop(struct seq_file *seq, void *v)
{
	mutex_unlock(&misc_mtx);
}

static int misc_seq_show(struct seq_file *seq, void *v)
{
	const struct miscdevice *p = list_entry(v, struct miscdevice, list);

	seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : "");
	return 0;
}


static const struct seq_operations misc_seq_ops = {
	.start = misc_seq_start,
	.next  = misc_seq_next,
	.stop  = misc_seq_stop,
	.show  = misc_seq_show,
};

static int misc_seq_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &misc_seq_ops);
}

static const struct file_operations misc_proc_fops = {
	.owner	 = THIS_MODULE,
	.open    = misc_seq_open,
	.read    = seq_read,
	.llseek  = seq_lseek,
	.release = seq_release,
};
#endif

static int misc_open(struct inode * inode, struct file * file)
{
	int minor = iminor(inode);
	struct miscdevice *c;
	int err = -ENODEV;
	const struct file_operations *new_fops = NULL;

	mutex_lock(&misc_mtx);

	list_for_each_entry(c, &misc_list, list) {
		if (c->minor == minor) {
			new_fops = fops_get(c->fops);
			break;
		}
	}

	if (!new_fops) {
		mutex_unlock(&misc_mtx);
		request_module("char-major-%d-%d", MISC_MAJOR, minor);
		mutex_lock(&misc_mtx);

		list_for_each_entry(c, &misc_list, list) {
			if (c->minor == minor) {
				new_fops = fops_get(c->fops);
				break;
			}
		}
		if (!new_fops)
			goto fail;
	}

	/*
	 * Place the miscdevice in the file's
	 * private_data so it can be used by the
	 * file operations, including f_op->open below
	 */
	file->private_data = c;

	err = 0;
	replace_fops(file, new_fops);
	if (file->f_op->open)
		err = file->f_op->open(inode,file);
fail:
	mutex_unlock(&misc_mtx);
	return err;
}

static struct class *misc_class;

static const struct file_operations misc_fops = {
	.owner		= THIS_MODULE,
	.open		= misc_open,
	.llseek		= noop_llseek,
};

/**
 *	misc_register	-	register a miscellaneous device
 *	@misc: device structure
 *
 *	Register a miscellaneous device with the kernel. If the minor
 *	number is set to %MISC_DYNAMIC_MINOR a minor number is assigned
 *	and placed in the minor field of the structure. For other cases
 *	the minor number requested is used.
 *
 *	The structure passed is linked into the kernel and may not be
 *	destroyed until it has been unregistered. By default, an open()
 *	syscall to the device sets file->private_data to point to the
 *	structure. Drivers don't need open in fops for this.
 *
 *	A zero is returned on success and a negative errno code for
 *	failure.
 */

int misc_register(struct miscdevice * misc)
{
	dev_t dev;
	int err = 0;
	bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR);

	INIT_LIST_HEAD(&misc->list);

	mutex_lock(&misc_mtx);

	if (is_dynamic) {
		int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
		if (i >= DYNAMIC_MINORS) {
			err = -EBUSY;
			goto out;
		}
		misc->minor = DYNAMIC_MINORS - i - 1;
		set_bit(i, misc_minors);
	} else {
		struct miscdevice *c;

		list_for_each_entry(c, &misc_list, list) {
			if (c->minor == misc->minor) {
				err = -EBUSY;
				goto out;
			}
		}
	}

	dev = MKDEV(MISC_MAJOR, misc->minor);

	misc->this_device =
		device_create_with_groups(misc_class, misc->parent, dev,
					  misc, misc->groups, "%s", misc->name);
	if (IS_ERR(misc->this_device)) {
		if (is_dynamic) {
			int i = DYNAMIC_MINORS - misc->minor - 1;

			if (i < DYNAMIC_MINORS && i >= 0)
				clear_bit(i, misc_minors);
			misc->minor = MISC_DYNAMIC_MINOR;
		}
		err = PTR_ERR(misc->this_device);
		goto out;
	}

	/*
	 * Add it to the front, so that later devices can "override"
	 * earlier defaults
	 */
	list_add(&misc->list, &misc_list);
 out:
	mutex_unlock(&misc_mtx);
	return err;
}

/**
 *	misc_deregister - unregister a miscellaneous device
 *	@misc: device to unregister
 *
 *	Unregister a miscellaneous device that was previously
 *	successfully registered with misc_register().
 */

void misc_deregister(struct miscdevice *misc)
{
	int i = DYNAMIC_MINORS - misc->minor - 1;

	if (WARN_ON(list_empty(&misc->list)))
		return;

	mutex_lock(&misc_mtx);
	list_del(&misc->list);
	device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
	if (i < DYNAMIC_MINORS && i >= 0)
		clear_bit(i, misc_minors);
	mutex_unlock(&misc_mtx);
}

EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);

static char *misc_devnode(struct device *dev, umode_t *mode)
{
	struct miscdevice *c = dev_get_drvdata(dev);

	if (mode && c->mode)
		*mode = c->mode;
	if (c->nodename)
		return kstrdup(c->nodename, GFP_KERNEL);
	return NULL;
}

static int __init misc_init(void)
{
	int err;
	struct proc_dir_entry *ret;

	ret = proc_create("misc", 0, NULL, &misc_proc_fops);
	misc_class = class_create(THIS_MODULE, "misc");
	err = PTR_ERR(misc_class);
	if (IS_ERR(misc_class))
		goto fail_remove;

	err = -EIO;
	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
		goto fail_printk;
	misc_class->devnode = misc_devnode;
	return 0;

fail_printk:
	printk("unable to get major %d for misc devices\n", MISC_MAJOR);
	class_destroy(misc_class);
fail_remove:
	if (ret)
		remove_proc_entry("misc", NULL);
	return err;
}
subsys_initcall(misc_init);

5.6.4.misc驅動框架原始碼分析2
5.6.4.1、open函式分析
5.6.4.2、misc在proc下的展現
5.6.4.3、核心互斥鎖
(1)何為互斥鎖
(2)定義:DEFINE_MUTEX
(3)上鎖mutex_lock和解鎖mutex_unlock
(4)核心防止競爭狀態的手段:原子訪問、自旋鎖、互斥鎖、訊號量
(5)原子訪問主要用來做計數、自旋鎖後面講中斷會詳細講、互斥鎖和訊號量很相似(其實就是計數值為1的訊號量),互斥鎖的出現比訊號量晚,實現上比訊號量優秀,儘量使用互斥鎖。

5.6.5.蜂鳴器驅動原始碼分析1
5.6.5.1、dev_init
(1)訊號量
(2)miscdevice
(3)gpio_request
(4)printk
5.6.5.2、ioctl
(1)為什麼需要ioctl(input output control,輸入輸出控制)。
(2)ioctl怎麼用

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <plat/regs-timer.h>
#include <mach/regs-irq.h>
#include <asm/mach/time.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
 
#include <linux/gpio.h>
 
#include <plat/gpio-cfg.h>
//#include <plat/regs-clock.h>
//#include <plat/regs-gpio.h>
 
//#include <plat/gpio-bank-e.h>
//#include <plat/gpio-bank-f.h>
//#include <plat/gpio-bank-k.h>
 
#define DEVICE_NAME     "buzzer"
 
#define PWM_IOCTL_SET_FREQ     1
#define PWM_IOCTL_STOP         0
 
static struct semaphore lock;	//定義一個訊號量
 
// TCFG0在Uboot中設定,這裡不再重複設定
// Timer0輸入頻率Finput=pclk/(prescaler1+1)/MUX1
//                     =66M/16/16
// TCFG0 = tcnt = (pclk/16/16)/freq;
// PWM0輸出頻率Foutput =Finput/TCFG0= freq
static void PWM_Set_Freq( unsigned long freq )
{
    unsigned long tcon;
    unsigned long tcnt;
    unsigned long tcfg1;
 
    struct clk *clk_p;
    unsigned long pclk;
 
    //unsigned tmp;
     
    //設定GPD0_2為PWM輸出
    s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(2));
 
    tcon = __raw_readl(S3C2410_TCON);
    tcfg1 = __raw_readl(S3C2410_TCFG1);
 
    //mux = 1/16
    tcfg1 &= ~(0xf<<8);
    tcfg1 |= (0x4<<8);
    __raw_writel(tcfg1, S3C2410_TCFG1);
     
    clk_p = clk_get(NULL, "pclk");
    pclk  = clk_get_rate(clk_p);
 
    tcnt  = (pclk/16/16)/freq;
     
    __raw_writel(tcnt, S3C2410_TCNTB(2));
    __raw_writel(tcnt/2, S3C2410_TCMPB(2));//佔空比為50%
 
    tcon &= ~(0xf<<12);
    tcon |= (0xb<<12);      //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0
    __raw_writel(tcon, S3C2410_TCON);
     
    tcon &= ~(2<<12);           //clear manual update bit
    __raw_writel(tcon, S3C2410_TCON);
}
 
void PWM_Stop( void )
{
    //將GPD0_2設定為input
    s3c_gpio_cfgpin(S5PV210_GPD0(2), S3C_GPIO_SFN(0));
}
 
static int x210_pwm_open(struct inode *inode, struct file *file)
{
    if (!down_trylock(&lock))
        return 0;
    else
        return -EBUSY;
     
}
 
 
static int x210_pwm_close(struct inode *inode, struct file *file)
{
    up(&lock);
    return 0;
}
 
// PWM:GPF14->PWM0
static int x210_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
    switch (cmd) 
    {
        case PWM_IOCTL_SET_FREQ:
            printk("PWM_IOCTL_SET_FREQ:\r\n");
            if (arg == 0)
                return -EINVAL;
            PWM_Set_Freq(arg);
            break;
 
        case PWM_IOCTL_STOP:
        default:
            printk("PWM_IOCTL_STOP:\r\n");
            PWM_Stop();
            break;
    }
 
    return 0;
}
 
 
static struct file_operations dev_fops = {
    .owner   =   THIS_MODULE,
    .open    =   x210_pwm_open,
    .release =   x210_pwm_close, 
    .ioctl   =   x210_pwm_ioctl,
};
 
static struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,	//255 系統自動分配次裝置號
    .name = DEVICE_NAME,	//裝置名字
    .fops = &dev_fops,	//file_operations結構體

            
           

相關推薦

5.linux驅動開發-6部分-5.6.misc裝置驅動

《5.linux驅動開發-第6部分-5.6.misc類裝置與蜂鳴器驅動》 第一部分、章節目錄 5.6.1.板載蜂鳴器驅動測試 5.6.2.misc類裝置介紹 5.6.3.misc驅動框架原始碼分析1 5.6.4.misc驅動框架原始碼分析2 5.6.5.蜂鳴器驅動原始碼分析1 5.6.6

6.misc裝置驅動

第三部分、隨堂記錄     1.板載蜂鳴器驅動測試 1.1、驅動部分 (1)九鼎移植核心已經提供了蜂鳴器驅動原始碼 (2)make menuconfig (3)bug排查。修改Makefile中的巨集名

linux驅動開發-11部分-5.11.網路裝置驅動介紹》

《linux驅動開發-第11部分-5.11.網路裝置驅動介紹》 第一部分、章節目錄 5.11.1.網路裝置驅動概述 5.11.2.虛擬網絡卡驅動分析1 5.11.3.虛擬網絡卡驅動分析2 5.11.4.DM9000驅動原始碼分析1 5.11.5.DM9000驅動原始碼分析2 第二部分

5.linux驅動開發-10部分-5.10.塊裝置驅動介紹》

《5.linux驅動開發-第10部分-5.10.塊裝置驅動介紹》 第一部分、章節目錄 5.10.1.正確理解塊裝置驅動的概念 5.10.2.塊裝置驅動框架簡介 5.10.3.塊裝置驅動案例分析1 5.10.4.塊裝置驅動案例分析2 5.10.5.塊裝置驅動案例分析3 第二部分、章節介

5.linux驅動開發-7部分-5.7.framebuffer驅動詳解》

《5.linux驅動開發-第7部分-5.7.framebuffer驅動詳解》 第一部分、章節目錄 5.7.1.framebuffer介紹 5.7.2.framebuffer應用程式設計實踐1 5.7.3.framebuffer應用程式設計實踐2 5.7.4.framebuffer應用程式

5.linux驅動開發-4部分-5.4.驅動框架入門之LED》

《5.linux驅動開發-第4部分-5.4.驅動框架入門之LED》 第一部分、章節目錄 5.4.1.何謂驅動框架 5.4.2.核心驅動框架中LED的基本情況 5.4.3.初步分析led驅動框架原始碼1 5.4.4.初步分析led驅動框架原始碼2 5.4.5.在核心中新增或去除某個驅動 5

5.linux驅動開發-3部分-5.3.字元裝置驅動高階》

《5.linux驅動開發-第3部分-5.3.字元裝置驅動高階》 第一部分、章節目錄 5.3.1.註冊字元裝置驅動新介面1 5.3.2.註冊字元裝置驅動新介面2 5.3.3.註冊字元裝置驅動新介面3 5.3.4.註冊字元裝置驅動新介面4 5.3.5.字元裝置驅動註冊程式碼分析1 5.3.6

5.linux驅動開發-2部分-5.2.字元裝置驅動基礎》

《5.linux驅動開發-第2部分-5.2.字元裝置驅動基礎》 第一部分、章節目錄 5.2.1.開啟驅動開發之路 5.2.2.最簡單的模組原始碼分析1 5.2.3.最簡單的模組原始碼分析2 5.2.4.最簡單的模組原始碼分析3 5.2.5.用開發板來除錯模組 5.2.6.字元裝置驅動工作

5.linux驅動開發-1部分-5.1.驅動應該怎麼學》

《5.linux驅動開發-第1部分-5.1.驅動應該怎麼學》 第一部分、章節目錄 5.1.1.什麼是驅動1 5.1.2.什麼是驅動2 5.1.3.模組化設計 5.1.4.linux裝置驅動分類 5.1.5.驅動程式的安全性要求 5.1.6.驅動應該這麼學 第二部分、章節介紹 5.1.

linux驅動開發驅動源碼分析(一)

linux 蜂鳴器 驅動 蜂鳴器的驅動源碼在/driver/char/buzzer/x210-buzzer.c文件中,源碼如下#include <linux/module.h> #include <linux/kernel.h> #include <linux

嵌入式Linux之我行——PWM在ARM Linux中的原理和驅動例項開發

嵌入式Linux之我行,主要講述和總結了本人在學習嵌入式linux中的每個步驟。一為總結經驗,二希望能給想入門嵌入式Linux的朋友提供方便。如有錯誤之處,謝請指正。 一、開發環境 主  機:VMWare--Fedora 9 開發板:Mini2440--64MB N

linux驅動開發10之misc驅動

1.板載蜂鳴器驅動測試 1.1驅動部分 1)九鼎移植核心已經提供了蜂鳴器驅動原始碼 2)make menuconfig 3)bug排查。修改Makefile中的巨集名,最終可以在系統中看到 /dev/buzzer 由於makefile檔案與Kconfig檔案中的

[S5PV210 Linux字元驅動之PWM驅動

在SMDK210.C中新增如下beeper_device 結構體 static struct platform_device beeper_device = {.name= "pwm_buzzer",.id         =  1,.dev= {.parent = &am

am335x_y驅動

ati b-s dev mach-o name ive () drivers app 修改文件:1、板級文件/arch/arm/mach-omap2/board-am335xevm.c static struct platform_device buzzer_device=

訊為4412驅動實現

最近在搞訊為開發板的驅動,終於將訊為的蜂鳴器驅動搞定,現在進行一個總結。 編寫流程: (1)分析硬體原理圖          要控制beep  ---->  gpd0_0   --->

高效驅動法:用定時掃描代替軟體延時

  上班跟上學果然不一樣,就比如一個蜂鳴器的驅動,學生時代寫蜂鳴器的程式倒也直觀:     PWM_SET(0x0a,0x80);//PWM0輸出4.24Khz,佔空比50%     Delay_ms(200);//延時200ms

5.linux驅動開發-5部分-5.8.input子系統基礎之按鍵》

《5.linux驅動開發-第5部分-5.8.input子系統基礎之按鍵》 第一部分、章節目錄 5.8.1.什麼是input子系統 5.8.2.input裝置應用層程式設計實踐1 5.8.3.input裝置應用層程式設計實踐2 5.8.4.input子系統架構總覽1 5.8.5.input

5.linux驅動開發-5部分-5.5.linux裝置驅動模型》

《5.linux驅動開發-第5部分-5.5.linux裝置驅動模型》 第一部分、章節目錄 5.5.1.linux裝置驅動模型簡介 5.5.2.裝置驅動模型的底層架構 5.5.3.匯流排式裝置驅動組織方式 5.5.4.platform平臺匯流排簡介1 5.5.5.platform平臺匯流排

linux操作指令 部分

groupdel 手動 左右 del cat pass useradd user 用戶操作 文件簡單操作 1.文件內容查看 > cat filename //一次性把全部內容都輸出到終端 > more filename

Linux驅動開發(3)——以module方式註冊裝置

通過 s3c_device_leds_ctl->*smdk4x12_devices[]->platform_add_devices()->platform_device_register() 可以直接使用“platform_device_register()”來註冊裝置