❶ linux与UNIX区别在哪
大家听别人介绍自己的Ubuntu时,会听到“我的操作系统是Linux的”。其实,这样介绍是缺乏严谨性滴。我们只要知道两点,基本上就搞清楚Linux和Ubuntu的关系,以下是星创客老师对二者的区别细节分析:
1. 严格来说,Linux并不是操作系统,而是一个操作系统的内核,严谨一些可以说:linux 一般指 GNU 套件加上 linux 内核。
2. Ubuntu基于linux内核的桌面PC操作系统,术语上喜欢称Ubuntu是一个 linux 发行版(因为debian(其实也是一款操作系统) 是 linux 的一个发行版,而 ubuntu 是属于 debian 系列的一个分支,所以...)。
深入理解下:
1. Linux应用程序
一个好的操作系统会提供一套方便于用户使用系统的应用程序,如文本编辑器、办公套件、Internet工具、数据库等。
2. Linux文件系统
文件系统是文件存放在存储设备(如磁盘)上的组织方法。如EXT2、EXT3、FAT、FAT32、VFAT等。
3. Linux Shell
Shell是操作系统系统的用户界面,提供了用户与内核进行交互操作的一种接口,是一个命令解释器。它接收用户输入的命令并把它送入内核去执行。
4. Linux内核
内核是操作系统的核心。一个操作系统是需要执行一些任务,如请求内存资源、执行计算, 连接网络,等等. Linux内核就负责处理所有这样的请求,就像人的大脑一样。
Linux内核从功能上讲具有五大模块化功能:进程管理、内存管理、文件系统管理、设备控制和网络管理。
4.1 进程管理的体现:
Linux内核负责进程创建和销毁, 并完成进程之间的通信,以及进程的输入和输出.而且,进程管理控制了多个进程对Soc上的一个或者多个cpu资源的使用
4.2 内存管理
内存资源的使用策略对操作系统性能体现来说,尤为重要。 内核在有限的内存资源上,为每一个进程建立了一个虚拟地址空间。 内核的不同功能部分与内存管理子系统通过一套函数调用交互, 使得通信高效简单。
4.3 文件系统管理
Linux操作系统中,几乎任何东西都可看作为一个文件(一切皆文件). 内核中大量使用kobject等结构体,来把一堆非结构化的硬件组织成一种多层次的数据系统。另外, Linux 支持多个文件系统类型。如ext4等
4.4 设备控制
几乎任何一个操作系统最终都运行在一个物理平台上。内核中包含访问平台上硬件设备的驱动代码。
4.5 网络功能
大部分网络操作不会关联具体的进程,因为数据包的传输是异步事件。应用程序访问数据包之前,内核完成数据包的收集、标识和分发等任务。
如果想学习嵌入式linux可以去了解下星创客还不错。
❷ Linux内核的功能是什么
内核是一个操作系统的核心,它负责管理系统的进程,内存,设备驱动程序,文件和网络系统,决定着系统的性能和稳定性。内核以独占的方式执行最底层任务,保证系统正常运行。协调多个并发进程,管理进程使用的内存,使它们相互之间不产生冲突,满足进程访问磁盘的请求等等.
严格说Linux并不能称做一个完整的操作系统.我们安装时通常所说的Linux,是有很多集合组成的.应称为GNU/Linux.
一个Linux内核很少1.2M左右,一张软盘就能放下.
❸ linux spi设备驱动中probe函数何时被调用
这两天被设备文件快搞疯了,也怪自己学东西一知半解吧,弄了几天总算能把设备注册理清楚一点点了。就以spi子设备的注册为例总结一下,免得自己忘记。
首先以注册一个spidev的设备为例:
static struct spi_board_info imx5_spi_printer_device[] __initdata =
{
{
.modalias = "spidev",
.max_speed_hz = 8000000,
.bus_num = 1,
.chip_select = 1,
.mode = SPI_MODE_0,
},
};
spi_register_board_info(imx5_spi_printer_device,ARRAY_SIZE(imx5_spi_printer_device));
在mx5_loco.c文件中添加上面结构体spi_board_info,modalias必须指定已有的一个驱动,至于bus_num和chip_select,如果你不知道bus_num是多少,可以在你的父驱动中打印出来,这里的bus_num一定要和父类的bus_num一致,否则是无法生成设备文件的。如果spi一直没有时钟信号,很有可能是bus_num不对。
这样系统起来之后就会在/dev目录下出现一个名为spidev1.1的设备文件,读写这个文件就可以实现spi的操作
还有下面这种情况:
static struct spi_board_info prt_spi_device[] __initdata = {
{
.modalias = "HotPRT",
.max_speed_hz = 12500000, /* max spi clock (SCK) speed in HZ */
.bus_num = 1,
.chip_select = 1,
// .mode = SPI_MODE_0,
.platform_data = 0,
},
};
spi_register_board_info(prt_spi_device, ARRAY_SIZE(prt_spi_device));
我自己实现了一个spi的驱动,然后需要创建一个设备文件,设备文件的创建是在probe中完成。
static struct spi_driver prt_driver = {
.driver = {
.name = "HotPRT",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = prt_probe,
.remove = __devexit_p(prt_remove),
};
spi_register_driver(&prt_driver);
但是我开始一直触发不了probe,于是找啊找,总算知道probe的调用过程了,如下:
int spi_register_driver(struct spi_driver *sdrv)
{
sdrv->driver.bus = &spi_bus_type;
if (sdrv->probe)
sdrv->driver.probe = spi_drv_probe;
if (sdrv->remove)
sdrv->driver.remove = spi_drv_remove;
if (sdrv->shutdown)
sdrv->driver.shutdown = spi_drv_shutdown;
return driver_register(&sdrv->driver);
}
然后调用driver_register
<pre name="code" class="cpp">int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);
if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret)
bus_remove_driver(drv);
return ret;
}
直接看bus_add_driver
klist_init(&priv->klist_devices, NULL, NULL);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
"%s", drv->name);
if (error)
goto out_unregister;
if (drv->bus->p->drivers_autoprobe) {
error = driver_attach(drv);
if (error)
goto out_unregister;
}
klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
mole_add_driver(drv->owner, drv);
这里只截取一部分,最后调用的是driver_attach
int driver_attach(struct device_driver * drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
真正起作用的是__driver_attach:
static int __driver_attach(struct device * dev, void * data)
{
。。。
if (!dev->driver)
driver_probe_device(drv, dev);
。。。
}
int driver_probe_device(struct device_driver * drv, struct device * dev)
{
。。。
//1.先是判断bus是否match:
if (drv->bus->match && !drv->bus->match(dev, drv))
goto done;
//2.再具体执行probe:
ret = really_probe(dev, drv);
。。。
}
really_probe才是我们要找的函数:
static int really_probe(struct device *dev, struct device_driver *drv)
{
。。。
//1.先是调用的驱动所属总线的probe函数:
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
//2.再调用你的驱动中的probe函数:
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
。。。
}
其中,drv->probe(dev),才是真正调用你的驱动实现的具体的probe函数。至此probe函数被调用。
在板文件中添加spi_board_info,并在板文件
❹ linux驱动编写过程中遇到的几个问题及解决
1、显示错误:unknown field 'ioctl' specified in initializer
解决办法,查看内核include/linux/fs.h文件,发现里边定义的struct file_operations中没有ioctl,这里我们用.unlocked_ioctl取代,形参去掉 struct inode*。
2、在应用程序中,将ioctl替换为unlocked_ioctl后,会出现以下错误:undefined reference to `unlocked_ioctl'。因为系统调用ioctl是没有改变的,还是原来的系统调用接口,只是系统调用的实现中,ioctl()变成了unlocked_ioctl,在应用层你根本不用关注内核中的这些实现上的改变,你只需要按照系统调用的用法用就可以了。所以把应用程序里的unlocked_ioctl改为ioctl,编译,OK,通过。
3、驱动编译完成,在开发板上insmod,出现以下错误:
WARNING: at lib/kobject.c:595 kobject_put+0x50/0x64()
kobject: '扑' (cbc60a00): is not initialized, yet kobject_put() is being called.
---[ end trace da227214a82491b9 ]---
insmod: cannot insert 'led_dev.ko': Cannot allocate memory
原来是忘了写内存申请的代码,添加kmalloc和memset。
4、再次insmod,出现下列错误代码:
Unable to handle kernel paging request at virtual address 7f008820
pgd = cbc70000
[7f008820] *pgd=00000000
Internal error: Oops: 5 [#1]
Moles linked in: led_dev(+)
CPU: 0 Tainted: G W (3.0.1 #439)
PC is at led_init+0xa8/0x108 [led_dev]
LR is at kobj_map+0x144/0x154
pc : [<bf0020a8>] lr : [<c0246e70>] psr: 60000013
sp : cbc6bf10 ip : cbc6beb0 fp : cbc6bf24
r10: 00000000 r9 : bf002000 r8 : cbc6a000
r7 : 00000000 r6 : bf0002bc r5 : 00000000 r4 : 00000000
r3 : 00000000 r2 : 00000000 r1 : 7f008000 r0 : 00000000
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 00c5387d Table: 5bc70008 DAC: 00000015
Process insmod (pid: 112, stack limit = 0xcbc6a268)
Stack: (0xcbc6bf10 to 0xcbc6c000)
bf00: 00000000 c07463c0 cbc6bf7c cbc6bf28
bf20: c00343c8 bf00200c cbc6bf64 cbc6bf38 c0073e24 00000000 00000000 00000000
bf40: 00000000 0000ef52 000d5bf9 bf0002bc 00000000 0000ef52 000d5bf9 bf0002bc
bf60: 00000000 c0034ce8 cbc6a000 00000000 cbc6bfa4 cbc6bf80 c0085960 c0034398
bf80: c00e8738 c00e8610 402004a8 000dfcf8 00000000 00000080 00000000 cbc6bfa8
bfa0: c0034b40 c00858e0 402004a8 000dfcf8 00b5d038 0000ef52 000d5bf9 ffff5f01
bfc0: 402004a8 000dfcf8 00000000 00000080 00000069 00000001 be9c2e64 be9c2e68
bfe0: be9c2e68 be9c2b14 00021cfc 402c1d74 60000010 00b5d038 5fffe821 5fffec21
[<bf0020a8>] (led_init+0xa8/0x108 [led_dev]) from [<c00343c8>] (do_one_initcall+0x3c/0x188)
[<c00343c8>] (do_one_initcall+0x3c/0x188) from [<c0085960>] (sys_init_mole+0x8c/0x1a4)
[<c0085960>] (sys_init_mole+0x8c/0x1a4) from [<c0034b40>] (ret_fast_syscall+0x0/0x30)
Code: e59f0060 eb52980e ea00000b e59f1058 (e5910820)
---[ end trace da227214a82491b9 ]---
Segmentation fault
最后是各种网络,各种谷歌,参考别人的驱动,发现它们的开发板硬件地址并不是自己写的头文件,而是调用mach中已经定义好的头文件,好吧,寻找相应开发板,相应端口的地址头文件,在驱动文件中添加以下头文件:
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank-m.h>
Ok,打完收工,开发板,测试。运行无阻。完成。
5、在做到DS18B20温度测试模块驱动的时候,看到网上的代码有些函数可以直接对引脚的功能进行设置,比如:s3c2410_gpio_cfgpin(DQ_PIN, DQ_PIN_OUTP); 但是对应于我的s3c6410的开发板就不知道用什么函数了,网上找了半天,发现以上函数是在#include <plat/gpio-cfg.h>中,6410中对应的函数为:extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to);
6、最近学习移植linux内核,移植了新的linux内核以及挂载了新的NFS之后, 重新测试led驱动,发现安装模块以后,运行测试程序会出现以下错误:
-/bin/sh: ./main: not found(main为主机上编译好的测试程序)
原因:
编译busybox的时候选择了静态编译:
Build Options->
Build BusyBox as a static binary (no shared libs)
Build with Large File Support (for accessing file>2GB)
如果选择 Build BusyBox as a static binary (no shared libs) 方式进行编译时,所需的库已经与程序静态地链接在一起,这些程序不需要额外的库就可以单独运行,但是自己编写的程序在文件系统上运行必须采用静态编译,否则会报诸如:bin/sh: main :not found的错误。
静态编译如:
arm-linux-gcc –static main.c –o main
7.按照普通方法安装配置tftp,并且关闭了防火墙,但是在开发板上tftp主机,总会报错:
tftp: server error: (0) Permission denied
解决办法:
修改文件 /etc/sysconfig/selinux,设定其中的
SELINUX=disabled
然后重启电脑即可
❺ linux 内核4.9.11如何使用热拔插
在Linux系统中,当系统配置发生变化时,如:添加kset到系统;移动kobject,一个通知会从内核空间发送到用户空间,这就是热插拔事件。热插拔事件会导致用户空间中相应的处理程序(如udev,mdev)被调用,这些处理程序会通过加载驱动程序,创建设备节点等来响应热插拔事件。
操作集合
Structkset_uevent_ops{
int(*filter)(structkset*kset,structkobject*kobj);
constchar*(*name)(structkset*kset,structkobject*kobj);
int(*uevent)(structkset*kset,structkobject*kobj,
structkobj_uevent_env*env);
}
当该kset所管理的kobject和kset状态发生变化时(如被加入,移动),这三个函数将被调用。
Filter:决定是否将事件传递到用户空间。如果filter返回0,将不传递事件。
Name:负责将相应的字符串传递给用户空间的热插拔处理程序。
Uevent:将用户空间需要的参数添加到环境变量中。
int(*uevent)(structkset*kset,
structkobject*kobj,/*产生事件的目标对象*/
char**envp,/*一个保存其他环境变量定义(通常为NAME=value的格式)的数组*/
intnum_envp,/*环境变量数组中包含的变量数(数组大小)*/
char*buffer,intbuffer_size/*环境变量被放入的缓冲区的指针和字节数*/
);/*返回值正常时是,若返回非零值将终止热插拔事件的产生*/
实例源码:temp.rar
点击(此处)折叠或打开
/**
*热插拔事件
*Lzy2012-7-27
*/
#include<linux/device.h>
#include<linux/mole.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/string.h>
#include<linux/sysfs.h>
#include<linux/stat.h>
#include<linux/kobject.h>
static struct attribute test_attr=
{
.name="kobj_config",
.mode=S_IRWXUGO,
};
static struct attribute*def_attrs[]=
{
&test_attr,
NULL,
};
ssize_t kobj_test_show(struct kobject*kobject,struct attribute*attr,char*buf)
{
printk("Have show -->
");
printk("attrname: %s.
",attr->name);
sprintf(buf,"%s
",attr->name);
return strlen(attr->name)+2;
}
ssize_t kobj_test_store(struct kobject*kobject,struct attribute*attr,constchar*buf,size_t size)
{
printk("Have store -->
");
printk("write: %s.
",buf);
return size;
}
static struct sysfs_ops obj_test_sysops=
{
.show=kobj_test_show,
.store=kobj_test_store,
};
void obj_test_release(struct kobject*kobject)
{
printk("[kobj_test: release!]
");
}
static struct kobj_type ktype=
{
.release=obj_test_release,
.sysfs_ops=&obj_test_sysops,
.default_attrs=def_attrs,
};
staticintkset_filter(struct kset*kset,struct kobject*kobj)
{
//intret=0;
//struct kobj_type*ktype=get_ktype(kobj);/*得到属性类型*/
//ret=(ktype==&ktype_part);
printk("Filter: kobj %s.
",kobj->name);
return 1;
}
staticconstchar*kset_name(struct kset*kset,struct kobject*kobj)
{
static char buf[20];
/*struct device*dev=to_dev(kobj);
if(dev->bus)
return dev->bus->name;
elseif(dev->class)
return dev->class->name;
else
*/{
printk("Name kobj %s.
",kobj->name);
sprintf(buf,"%s","kset_name");
}
return buf;
}
staticintkset_uevent(struct kset*kset,struct kobject*kobj,struct kobj_uevent_env*env)
{
inti=0;
printk("uevent: kobj %s.
",kobj->name);
while(i<env->envp_idx)
{
printk("%s.
",env->envp[i]);
i++;
}
return 0;
}
static struct kset_uevent_ops uevent_ops=
{
.filter=kset_filter,
.name=kset_name,
.uevent=kset_uevent,
};
struct kset*kset_p;
struct kset kset_c;
staticint__init kset_test_init(void)
{
intret=0;
printk("kset test init!
");
/*创建并注册 kset_p*/
kset_p=kset_create_and_add("kset_p",&uevent_ops,NULL);
kobject_set_name(&kset_c.kobj,"kset_c");
kset_c.kobj.kset=kset_p;/*添加 kset_c 到 kset_p*/
/*对于较新版本的内核,在注册 kset 之前,需要
*填充 kset.kobj 的 ktype 成员,否则注册不会成功*/
kset_c.kobj.ktype=&ktype;
ret=kset_register(&kset_c);
if(ret)
kset_unregister(kset_p);
return ret;
}
static void __exit kset_test_exit(void)
{
printk("kset test exit!
");
kset_unregister(&kset_c);
kset_unregister(kset_p);
}
mole_init(kset_test_init);
mole_exit(kset_test_exit);
MODULE_AUTHOR("Lzy");
MODULE_LICENSE("GPL");