世事艱難,人生不易。 夜深人靜時候,回顧過去,往事歷歷在目。創南京,混蘇州,下上海。都付出了巨大的努力。多少個不眠的夜晚,在左思右想。天生愚鈍。又不是學計算機的。一直沒較爲深入的理解node
編程什麼東西,一直沒有入門。linux
感謝Qisda, 讓我在08年就開始接觸android. 都不容易。android
編程是什麼?編程
編程是數據處理。如何處理? cpu經過指令指針的跳轉,實現了讀下一條指令,cpu實現了讀指令,編譯指令。ubuntu
感謝marvell. 哎marvell技術 不可謂不強。認識一大批牛人。jialin, jiaguo, xinjiang wenzhao fuqiang ruikuang xia . 哎,咱們一個team。我是最菜的。一個上海交大,一個武大,一個哈工大。一個南大。
一箇中國科大少年班。南航和他們比太菜了。哎。 就不斷的琢磨。學習
仍是老套路把。先從簡單字符驅動開始。測試
驅動是爲了溝通os和硬件。起到了承上啓下的做用。哪就說明這個模塊就能讓os認識它。有能操做硬件。ui
那如何讓os認識它呢?spa
就一句話int cdev_add(struct cdev *p, dev_t dev, unsigned count).
那這些參數哪來的呢?操作系統
struct cdev就須要本身建立結構體內存。 dev_t是分配的設備號。
struct globalmem_dev{
struct cdev cdev;
unsigned char mem[GLOBALMEM_SIZE];
};
這樣就建立了這個結構體。初始化時候分配內存就行了。爲何要弄個結構體。弄個靜態全局變量能夠嗎? 也能夠的 。可是不太方便。爲何不方便呢? 下面說
還要分配設備號
if (globalmem_major){
result = register_chrdev_region(devno, 2, "globalmem");
}else {
result = alloc_chrdev_region(&devno,0, 2, "globalmem");
globalmem_major = MAJOR(devno);
}
有了cdev dev_t. 就能夠添加到os了。
爲何參數要有個設備號呢? 系統有不少的驅動,應用程序只看到設備節點。當應用open的時候,系統會看大這個設備的設備號。根據設備號找對應的驅動。因此add的時候須要跟上設備號。
cdev初始化還要加上fop。
static const struct file_operations globalmem_fops = {
.owner = THIS_MODULE,
.llseek = globalmem_llseek,
.read = globalmem_read,
.write = globalmem_write,
.unlocked_ioctl = globalmem_ioctl,
.open = globalmem_open,
.release = globalmem_release,
};
當應用call open的時候,操做系統會先作一些通用的處理。作什麼通用的處理我也不清楚,正在學習,不知道就不知道。千萬別像書上寫的。這裏通常用不到。沒必要了解。不瞭解中國人怎麼寫出操做系統來?
作通用處理的時候會產生inode file兩個結構體。 同時把file的fop的控件用驅動的add的cdev裏的fop初始化。哪確定的,否則之後read write時候參數都有file指針,那系統如何找到咱們驅動的真正的read write
實現呢?
static int globalmem_open(struct inode *inode, struct file *filp){
struct globalmem_dev *dev;
dev = container_of(inode->i_cdev, struct globalmem_dev, cdev);
filp->private_data = dev;
printk(KERN_ALERT "globalmem_open!");
return 0;
}
dev = container_of(inode->i_cdev, struct globalmem_dev, cdev);
filp->private_data = dev;
這兩句話看清楚了嗎? 使勁理解。
下面把個人測試代碼發出來把
#include<linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
//#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
MODULE_AUTHOR("qcom.shanghai@gmail.com");
MODULE_LICENSE("Dual BSD/GPL");
#define GLOBALMEM_SIZE 0X1000
#define MEM_CLEAR 0x1
static int globalmem_major = 0;
struct globalmem_dev{
struct cdev cdev;
unsigned char mem[GLOBALMEM_SIZE];
};
struct globalmem_dev *globalmem_devp;
static int globalmem_open(struct inode *inode, struct file *filp){
struct globalmem_dev *dev;
dev = container_of(inode->i_cdev, struct globalmem_dev, cdev);
filp->private_data = dev;
printk(KERN_ALERT "globalmem_open!");
//marvell 臧春傑
return 0;
}
static int globalmem_release(struct inode *inode, struct file *filp){
printk(KERN_ALERT "globalmem_release!");
return 0;
}
static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos){
unsigned long p = *ppos;
unsigned int count = size;
int ret = 0;
struct globalmem_dev *dev = filp->private_data;
if (p >= GLOBALMEM_SIZE){
return 0;
}
if (count > GLOBALMEM_SIZE - p){
count = GLOBALMEM_SIZE - p;
}
if (copy_to_user(buf, (void *)(dev->mem + p), count)){
ret = - EFAULT;
}else {
*ppos += count;
ret = count;
printk(KERN_ALERT "read %u bytes from %lu \n", count, p);
}
return ret;
}
static ssize_t globalmem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos){
unsigned long p = *ppos;
unsigned int count = size;
//marvell 臧春傑
int ret = 0;
struct globalmem_dev *dev = filp->private_data;
if (p >= GLOBALMEM_SIZE){
return 0;
}
if (count > GLOBALMEM_SIZE - p){
count = GLOBALMEM_SIZE - p;
}
if (copy_from_user(dev->mem + p, buf, count)){
ret = - EFAULT;
}else {
*ppos += count;
ret = count;
printk(KERN_ALERT "write %u bytes from %lu \n", count, p);
}
return ret;
}
static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig){
loff_t ret = 0;
switch(orig){
case 0:
if (offset < 0){
ret = - EFAULT;
break;
}
if ((unsigned int)offset > GLOBALMEM_SIZE){
ret = - EFAULT;
break;
}
filp->f_pos = (unsigned int) offset;
ret = filp->f_pos;
break;
case 1:
if ((filp->f_pos + offset) > GLOBALMEM_SIZE){
ret = - EFAULT;
//marvell 臧春傑
break;
}
if ((filp->f_pos + offset) < 0){
ret = - EFAULT;
break;
}
filp->f_pos += offset;
ret = filp->f_pos;
break;
default:
ret = - EFAULT;
break;
}
return ret;
}
static long globalmem_ioctl(struct file *flip, unsigned int cmd, unsigned long arg){
printk(KERN_ALERT "globalmem_ioctl");
return 10L;
}
static const struct file_operations globalmem_fops = {
.owner = THIS_MODULE,
.llseek = globalmem_llseek,
.read = globalmem_read,
.write = globalmem_write,
.unlocked_ioctl = globalmem_ioctl,
.open = globalmem_open,
.release = globalmem_release,
};
static void globalmem_setup_cdev(struct globalmem_dev *dev, int index){
int err, devno = MKDEV(globalmem_major, index);
cdev_init(&(dev->cdev), &globalmem_fops);
dev->cdev.owner = THIS_MODULE; //marvell 臧春傑
err = cdev_add(&dev->cdev, devno, 1);
if (err){
printk(KERN_ALERT"cdev_add failed!");
}
}
static int __init globalmem_init(void){
int result;
dev_t devno = MKDEV(globalmem_major, 0);
if (globalmem_major){
result = register_chrdev_region(devno, 2, "globalmem");
}else {
result = alloc_chrdev_region(&devno,0, 2, "globalmem");
globalmem_major = MAJOR(devno);
}
printk(KERN_ALERT "major-------------->%d \n", globalmem_major);
if (result < 0){
return result;
}
globalmem_devp = kmalloc(2 * sizeof(struct globalmem_dev), GFP_KERNEL);
if (! globalmem_devp){
result = -ENOMEM;
goto fail_malloc;
}
memset(globalmem_devp, 0, 2 * sizeof(struct globalmem_dev));
globalmem_setup_cdev(&globalmem_devp[0], 0);
//marvell 臧春傑
globalmem_setup_cdev(&globalmem_devp[1], 1);
return 0;
fail_malloc:
//marvell 臧春傑
unregister_chrdev_region(devno, 1);
return result;
}
static void __exit globalmem_exit(void){
cdev_del(&globalmem_devp[0].cdev);
cdev_del(&globalmem_devp[1].cdev);
kfree(globalmem_devp);
unregister_chrdev_region(MKDEV(globalmem_major, 0), 2);
}
module_param(globalmem_major, int, S_IRUGO);
module_init(globalmem_init);
module_exit(globalmem_exit);
這個代碼我在ubuntu16.04上編譯測試過。
結果以下
[ 443.797578] major-------------->247
[ 593.833449] globalmem_open!
[ 593.833486] write 13 bytes from 0
[ 593.833499] globalmem_release!
[ 620.507565] globalmem_open!
[ 620.507659] read 4096 bytes from 0
[ 620.509053] globalmem_release!
[ 647.025424] globalmem_open!
[ 647.025465] write 16 bytes from 0
[ 647.025475] globalmem_release!
[ 650.531294] globalmem_open!
[ 650.531327] read 4096 bytes from 0
能夠直接拷貝,寫個makefile編譯,後續我再加點自動建立設備節點。就不用本身mknod了。
不吃苦中苦,難爲人上人。千萬別成王寶強。