❶ 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");