1. linux驅動與設備節點簡介 & Android內核與Linux內核的區別
驅動是內核的一部分,作為直接訪問物理硬體的一個軟體層,用於應用程序與物理硬體設備通信。內核包含多種驅動,如WIFI、USB、Audio、藍牙、相機、顯示驅動。
(1)設備驅動程序三類:字元設備驅動程序、塊設備驅動程序、網路設備驅動程序;
(2)對應Linux三類設備:字元設備、塊設備、網路設備;
(3)常見字元設備:滑鼠、鍵盤、串口、控制台等;
(4)常見塊設備:各種硬碟、flash磁碟、RAM磁碟等;
(5)網路設備(網路介面):eth0、eth1,註:網路設備沒有設備節點,應用程序通過Socket訪問網路設備。由於網路設備面向報文,較難實現相關read、write等文件讀寫函數,所以驅動的實現也與字元設備和塊設備不同。
Linux使用對文件一樣的管理方式來管理設備,所有設備都以文件的形式存放在/dev目錄下,系統中的每個字元設備或者塊設備都必須為其創建一個設備文件,它包含了該設備的設備類型(塊設備或字元設滾橋備)、設備號(主設備號和次設備號)以及設備訪問控制屬性等。設備節點通過 mknod 命令創建,也可以由Udev用戶工具軟體在系統啟動後根據/sys目錄下每個設備的實際信息創建,使用後一種方式可以為每個設備動態分配設備號。
Linux中設備節點通過「mknod」命令創建,創建時需要指定主設備號和次設備號,即指定對應的驅動程序和對應的物理設備(訪問設備節點時就相當於通過其設備號訪問驅動程序進而間接訪問到物理設備)。主設備號用來區分不同種類的設備,而次設備號用來區分同一類大舉猛型的多個設備。對於常用設備,Linux有約定俗成的編號,如硬碟的主設備號是3
理解:應用程序通過訪問設備節點讀取主設備號和次設備號,通過主設答枯備號找對應的驅動,通過次設備號對應到具體物理設備。註:1個驅動對應一類設備,並用唯一主設備號標識。
Linux支持的各種設備的主設備號定義在include/linux/major.h文件中,已經在官方注冊的主設備號和次設備號在Documentation/devices.txt文件中。
Android系統最底層是Linux,並且在中間加上了一個Dalvik / ART的Java虛擬機,從表面層看是Android運行庫。每個Android應用都運行在自己的進程上,享有Dalvik / ART虛擬機為它分配的專有實例,並支持多個虛擬機在同一設備上高效運行,虛擬機執行的是專有格式的可執行文件(.dex) - 該格式經過優化,以將內存好用降到最低。
Android內核和Linux內核的差別主要體現在如下11個方面:
2. Linux常用命令
常用的命令有好多啊,你剛開始學,不用特意的去記,用到什麼學什麼就好了。 當然非要列舉,下面列舉的100條,是來自網路經驗上的。 希望對你有幫助。
Linux常用命令大全100條:
1,echo 「aa」 》 test.txt 和 echo 「bb」 》》 test.txt
//》將原文件清空,並且內容寫入到文件中,》》將內容放到文件的尾部
2,chmod go+w -R /home/zhangy //給組用戶和其他用戶添加寫的許可權
3,tar -tzvf test.tar.gz //列出歸檔內容
4, -ah //查看文件列表大小
5, -sh //查看所有文件的大小總和
6,echo 『1+2』|bc -l //數學運算
7,uname -a //查看linux內核等的一些信息
8,badblocks -s /dev/sda //壞道掃描時顯示進度
9,time command //查看命令的運行時間
10,ls -lrt //按時間的倒序排序
11,rsync -P //同步時顯示進度
12.history -c //清楚歷史命令
13,cd - //返回上次目錄
14,tree //顯示目錄樹
15,umount -n /mnt/hda2 //強制卸載
16,echo ~/ //顯示用戶的home目錄
17,echo $[5*5] //算術運算
18,echo $((5*5)) //算術運算
19,eval ls;ps aux|grep httpd //這二個命令都能執行
20,free -m //有MB為單位顯示內存
21,uptime
//顯示系統已經運行了多長時間,它依次顯示下列信息:現在時間、系統已經運行了多長時間、目前有多少登陸用戶、系統在過去的1分鍾、5分鍾和15分鍾內的平均負載
22,加法運算
[root@krlcgcms01 mytest]# let a=34+3;
[root@krlcgcms01 mytest]# echo $a;
23,export //查看所有環境變數
24,echo $PATH //查看單個變數
25,cmp file1 file2 //文件內容比對
26,clear //清屏
27,echo 23423 |awk --re-interval 『/[0-9]{3,}/』 //如果不加re-interval的話,不顯示
28,cal //得到一個整齊的日歷格式
29,wc -l //統計行數,wc -w 統計單詞
30,echo 「AaDCbd23」 |tr 「[A-Z]」 「[a-z]」 大寫變小寫,echo 「AaDCbdc23」 |tr -c b-d =
將b-d之外的字元串替換成=
31,echo 「ADSF」 | iconv -f UTF8 -t GBK //把字元由utf8轉成gbk
-f是from和簡寫,-t好像terminal的簡寫
32,cat -n file //內容的前面會顯示行號
33,chattr +i file //只讀,root用戶也沒法對其進行修改
34,lsattr file //查看文件屬性
35,cat /etc/passwd |awk -F: 『{print $1}』 //查看系統中所有用戶
36,cat /etc/group //查看系統中所有的組
37,groups //查前當前用戶所在的,所有組
38,usermod -g 組名 用戶 //這種方式是覆蓋的方式,用的時候要小心,如果用戶A性於mysql usermod -g php
mysql這樣的話只屬於php了
39,usermod -G 組名 用戶 //這種方式是增加的方式,如果用戶A性於mysql usermod -g php
mysql這樣的話,mysql就屬於2個組了
40,bc //進入數學計算中去
41,umask 003 u許可權是7,g許可權是7,其他用戶是4,也就是774,777-003=774
42,mkfs -t vfat /dev/hda6 //將移動硬碟裡面的一個分區格式化成vfat格式
43,mount /dev/cdrom /media/cdrom //掛載cdrom
44,getent group 532 //通過組ID,來查找組信息
45,last //登錄成功用戶記錄
46,lastb //登錄不成功用戶記錄
47,mp -S /dev/sda2 //查看一下要備份/dev/sda2所要的容量
48,mp -0j -f /dev/hda2/sda2_bak.mp.bz2 /dev/sda2 //將sda2進行備份並壓縮
49,restore -t -f /dev/hda2/sda2_bak.mp //查看備份信息
50,restore -r -f /dev/hda2/sda2_bak.mp //還原備份
51,fc-list //查看系統中安裝的字體
52,find 。/ -type f -exec grep -q 「root」 {} ; -exec echo {} ;
//查找目錄下文件所包涵的字元串
53,vmstat 5 //每5顯示一下次系統信息,cpu,memory,i/o等
54,top 後 在shift + P 所佔進程的排序顯示
55,top 後 在shift + M 所佔內存的排序顯示
56,iptraf -g //查看各個介面的流量
57,ostat -d -x /dev/sda2 2 //用iostat查看磁碟/dev/sda2的磁碟i/o情況,每兩秒刷新一次
58, paste -sd 『|||n』 test //文件的每4行轉換成1行,並用|隔開
59,lsof -i :22 //知道22埠現在運行什麼程序
60,lsof -c abc //顯示abc進程現在打開的文件
61,lsof -p 12 //看進程號為12的進程打開了哪些文件
63,route //查看路由信息
64,ifup //開啟網卡
65,ifdown //關閉網卡
66,route del -net 172.168.0.0 netmask 255.255.0.0 dev eth0 //刪除
172.168這個網段
67,route add -net 172.168.10.0 netmask 255.255.255.0 dev eth0 //增加一個路由
68,netstat -tunl //列出監聽的網路服務埠
69,netstat -tun //列出已連接的網路服務埠
70,nmap -sP 172.30.4.0/24 //在這個網段內有多少用戶在我的主機上操作,一個不錯的安全檢查工具
71,vgdisplay //查看系統中的可用空間
72,lvextend -L+20G /dev/tank/part1 //向part1這個分區增加20G的空間
73,lvresize -L-10G /dev/tank/part2 //向part2這個分區減少10G的空間
74,pvdisplay //查看磁碟信息
75,mplayer -loop 10 /mnt/song/music/花兒開了.mp3 //循環播放10遍
76,pacman -S firefox -nd //nd去掉依賴
77,wget -c //斷點下載
78,chroot /mnt/ubuntu //改變根目錄到/mnt/ubuntu
79,ctrl+a //命令行下,游標稱動到開頭
80,ctrl+e //命令行下,游標移動結尾
81,cut -d: -f 1-4 test //用:分割文件,取分割後的1-4列
82,file /home/zhangy/test.php //用於查看文件的一些基本信息
83,touch test.txt //創建一個空文件 text.txt
84,htpasswd -cbd /usr/local/nginx/conf/authfile //創建訪問控制文件
85,df //查看磁碟空間,和當前的磁碟數
86,fdisk -l //查看所有磁碟數
87,alsamixer //進入後,m鍵可以實現靜音
88,killall httpd //把所有httpd進程殺掉
89,killall -9 mysqld_safe //有些進程超級用戶也停止不了,-9是強制刪除
90,mirror /mysql //下載mysql目錄
91,mirror -R /mysql //上傳mysql目錄
92,rmmod pcspkr //關掉tab提示音
93,modprobe pcspkr //開啟tab提示音
94,gpasswd -a zhangy wheel //將zhangy這個用戶添加到wheel這個組
95,dd if=/dev/zero of=/virtual/ubuntu.virt.img bs=1M count=4096
//創建一個4G的IMG鏡像
96,lspic //顯示pci設備
97,lsusb //顯示usb設備
98,history | less //less根more有點像,感覺less用著更舒服點
99,ln -s //如果忘了-s就變成硬鏈接了
100,tar zxvf test.tar.gz -C /home/zhangy //將內容解壓到指定目錄
3. Debian linux中有一個不能識別的硬體,找到有人在github上的驅動源碼,如何安裝到系統中。
./configure
./make
./make install
不對啊,你這個鏈接是內核源碼的代碼,編譯安裝這個得需要編譯內核。
下載你的系統內核源碼,然後編譯安裝系統內核吧。
具體的操作步驟度娘知道。
4. 在紅旗6.0linux系統Realtek High Definition Audio音效卡下無法使用耳機
可能是耳機插頭和耳機插孔不匹配的原因,建議更換耳機,我以前也遇到過,換一耳機就沒事。不過我的本本是「聯想」的。可以一試。
5. 怎樣寫linux下的USB設備驅動程序
寫一個USB的驅動程序最 基本的要做四件事:驅動程序要支持的設備、注冊USB驅動程序、探測和斷開、提交和控制urb(USB請求塊)
驅動程序支持的設備:有一個結構體struct usb_device_id,這個結構體提供了一列不同類型的該驅動程序支持的USB設備,對於一個只控制一個特定的USB設備的驅動程序來說,struct usb_device_id表被定義為:
/* 驅動程序支持的設備列表 */
static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ } /* 終止入口 */
};
MODULE_DEVICE_TABLE (usb, skel_table);
對 於PC驅動程序,MODULE_DEVICE_TABLE是必需的,而且usb必需為該宏的第一個值,而USB_SKEL_VENDOR_ID和 USB_SKEL_PRODUCT_ID就是這個特殊設備的製造商和產品的ID了,我們在程序中把定義的值改為我們這款USB的,如:
/* 定義製造商和產品的ID號 */
#define USB_SKEL_VENDOR_ID 0x1234
#define USB_SKEL_PRODUCT_ID 0x2345
這兩個值可以通過命令lsusb,當然你得先把USB設備先插到主機上了。或者查看廠商的USB設備的手冊也能得到,在我機器上運行lsusb是這樣的結果:
Bus 004 Device 001: ID 0000:0000
Bus 003 Device 002: ID 1234:2345 Abc Corp.
Bus 002 Device 001: ID 0000:0000
Bus 001 Device 001: ID 0000:0000
得到這兩個值後把它定義到程序里就可以了。
注冊USB驅動程序:所 有的USB驅動程序都必須創建的結構體是struct usb_driver。這個結構體必須由USB驅動程序來填寫,包括許多回調函數和變數,它們向USB核心代碼描述USB驅動程序。創建一個有效的 struct usb_driver結構體,只須要初始化五個欄位就可以了,在框架程序中是這樣的:
static struct usb_driver skel_driver = {
.owner = THIS_MODULE,
.name = "skeleton",
.probe = skel_probe,
.disconnect = skel_disconnect,
.id_table = skel_table,
};
探測和斷開:當 一個設備被安裝而USB核心認為該驅動程序應該處理時,探測函數被調用,探測函數檢查傳遞給它的設備信息,確定驅動程序是否真的適合該設備。當驅動程序因 為某種原因不應該控制設備時,斷開函數被調用,它可以做一些清理工作。探測回調函數中,USB驅動程序初始化任何可能用於控制USB設備的局部結構體,它 還把所需的任何設備相關信息保存到一個局部結構體中,
提交和控制urb:當驅動程序有數據要發送到USB設備時(大多數情況是在驅動程序的寫函數中),要分配一個urb來把數據傳輸給設備:
/* 創建一個urb,並且給它分配一個緩存*/
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
retval = -ENOMEM;
goto error;
}
當urb被成功分配後,還要創建一個DMA緩沖區來以高效的方式發送數據到設備,傳遞給驅動程序的數據要復制到這塊緩沖中去:
buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
if (!buf) {
retval = -ENOMEM;
goto error;
}
if (_from_user(buf, user_buffer, count)) {
retval = -EFAULT;
goto error;
}
當數據從用戶空間正確復制到局部緩沖區後,urb必須在可以被提交給USB核心之前被正確初始化:
/* 初始化urb */
usb_fill_bulk_urb(urb, dev->udev,
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, count, skel_write_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
然後urb就可以被提交給USB核心以傳輸到設備了:
/* 把數據從批量OUT埠發出 */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
goto error;
}
當urb被成功傳輸到USB設備之後,urb回調函數將被USB核心調用,在我們的例子中,我們初始化urb,使它指向skel_write_bulk_callback函數,以下就是該函數:
static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
{
struct usb_skel *dev;
dev = (struct usb_skel *)urb->context;
if (urb->status &&
!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN)) {
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
}
/* 釋放已分配的緩沖區 */
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
}
有時候USB驅動程序只是要發送或者接收一些簡單的數據,驅動程序也可以不用urb來進行數據的傳輸,這是里涉及到兩個簡單的介面函數:usb_bulk_msg和usb_control_msg ,在這個USB框架程序里讀操作就是這樣的一個應用:
/* 進行阻塞的批量讀以從設備獲取數據 */
retval = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, count),
&count, HZ*10);
/*如果讀成功,復制到用戶空間 */
if (!retval) {
if (_to_user(buffer, dev->bulk_in_buffer, count))
retval = -EFAULT;
else
retval = count;
}
usb_bulk_msg介面函數的定義如下:
int usb_bulk_msg(struct usb_device *usb_dev,unsigned int pipe,
void *data,int len,int *actual_length,int timeout);
其參數為:
struct usb_device *usb_dev:指向批量消息所發送的目標USB設備指針。
unsigned int pipe:批量消息所發送目標USB設備的特定端點,此值是調用usb_sndbulkpipe或者usb_rcvbulkpipe來創建的。
void *data:如果是一個OUT端點,它是指向即將發送到設備的數據的指針。如果是IN端點,它是指向從設備讀取的數據應該存放的位置的指針。
int len:data參數所指緩沖區的大小。
int *actual_length:指向保存實際傳輸位元組數的位置的指針,至於是傳輸到設備還是從設備接收取決於端點的方向。
int timeout:以Jiffies為單位的等待的超時時間,如果該值為0,該函數一直等待消息的結束。
如果該介面函數調用成功,返回值為0,否則返回一個負的錯誤值。
usb_control_msg介面函數定義如下:
int usb_control_msg(struct usb_device *dev,unsigned int pipe,__u8 request,__u8requesttype,__u16 value,__u16 index,void *data,__u16 size,int timeout)
除了允許驅動程序發送和接收USB控制消息之外,usb_control_msg函數的運作和usb_bulk_msg函數類似,其參數和usb_bulk_msg的參數有幾個重要區別:
struct usb_device *dev:指向控制消息所發送的目標USB設備的指針。
unsigned int pipe:控制消息所發送的目標USB設備的特定端點,該值是調用usb_sndctrlpipe或usb_rcvctrlpipe來創建的。
__u8 request:控制消息的USB請求值。
__u8 requesttype:控制消息的USB請求類型值。
__u16 value:控制消息的USB消息值。
__u16 index:控制消息的USB消息索引值。
void *data:如果是一個OUT端點,它是指身即將發送到設備的數據的指針。如果是一個IN端點,它是指向從設備讀取的數據應該存放的位置的指針。
__u16 size:data參數所指緩沖區的大小。
int timeout:以Jiffies為單位的應該等待的超時時間,如果為0,該函數將一直等待消息結束。
如果該介面函數調用成功,返回傳輸到設備或者從設備讀取的位元組數;如果不成功它返回一個負的錯誤值。
這兩個介面函數都不能在一個中斷上下文中或者持有自旋鎖的情況下調用,同樣,該函數也不能被任何其它函數取消,使用時要謹慎。
我們要給未知的USB設備寫驅動程序,只需要把這個框架程序稍做修改就可以用了,前面我們已經說過要修改製造商和產品的ID號,把0xfff0這兩個值改為未知USB的ID號。
#define USB_SKEL_VENDOR_ID 0xfff0
#define USB_SKEL_PRODUCT_ID 0xfff0
還 有就是在探測函數中把需要探測的介面端點類型寫好,在這個框架程序中只探測了批量(USB_ENDPOINT_XFER_BULK)IN和OUT端點,可 以在此處使用掩碼(USB_ENDPOINT_XFERTYPE_MASK)讓其探測其它的端點類型,驅動程序會對USB設備的每一個介面進行一次探測, 當探測成功後,驅動程序就被綁定到這個介面上。再有就是urb的初始化問題,如果你只寫簡單的USB驅動,這塊不用多加考慮,框架程序里的東西已經夠用 了,這里我們簡單介紹三個初始化urb的輔助函數:
usb_fill_int_urb :它的函數原型是這樣的:
void usb_fill_int_urb(struct urb *urb,struct usb_device *dev,
unsigned int pipe,void *transfer_buff,
int buffer_length,usb_complete_t complete,
void *context,int interval);
這個函數用來正確的初始化即將被發送到USB設備的中斷端點的urb。
usb_fill_bulk_urb :它的函數原型是這樣的:
void usb_fill_bulk_urb(struct urb *urb,struct usb_device *dev,
unsigned int pipe,void *transfer_buffer,
int buffer_length,usb_complete_t complete)
這個函數是用來正確的初始化批量urb端點的。
usb_fill_control_urb :它的函數原型是這樣的:
void usb_fill_control_urb(struct urb *urb,struct usb_device *dev,unsigned int pipe,unsigned char *setup_packet,void *transfer_buffer,int buffer_length,usb_complete_t complete,void *context);
這個函數是用來正確初始化控制urb端點的。
還有一個初始化等時urb的,它現在還沒有初始化函數,所以它們在被提交到USB核心前,必須在驅動程序中手工地進行初始化,可以參考內核源代碼樹下的/usr/src/~/drivers/usb/media下的konicawc.c文件。
6. linux audio micphone alsa 怎麼判斷插入
需求:USB Headset插上去後,聲音要從本地CODEC切換到USB Headset輸出/輸入。
上網搜了有關USB Audio Hotplug的東西,比較適用的資源如下:1、Hotplugging USB audio devices (Howto)
題目看起來很吻合我們的問題,事實上並沒有多少參考價值。其中腳本
/etc/hotplug/usb/extigy或許可以捕捉到USB Audio設備的熱插拔事件則隱,應該可以進一步驗證和利用,留意這點。
2、Example to map USB Ports to ALSA card numbers and
add each sound card to a combined, single interface device
這是利用udev來獲取USB熱插拔事件,雖然Android沒有udev,但例子程序對熱插拔事件字元串的處理值得參考。
3、USB mic on Linux
其實我們工作的第一步:驗證USB Headset是否可以回放錄音。
3.1、插上USB Headset,可以看到alsa的確載入了USB Audio,如下:
~ # cat /proc/asound/cards
0 [WMTSOC ]: HWDAC - WMT_SOC
WMT_SOC (HWDAC)
1 [default ]: USB-Audio - C-Media USB Headphone Set
3.2、參考了這個鏈接,寫了如下的配置文件/etc/asond.conf:
pcm.!default {type asymplayback.pcm {type plugslave.pcm hw:1,0}capture.pcm {type plugslave.pcm hw:1,0}}
重啟後,聲音就從Headset出來了。
hw:1,0對應card1即USB-Audio - C-Media USB Headphone Set4、Linux下USB設備熱插拔
到此,需要考慮在Android平台切換USB Audio的實現問題了。有幾個途徑:1/
hotplug/usb;2/ udev;3/ netlink。這里就是netlink的實現方式,鏈接里有個證實可用的例子程序,目前可能需要做熱插拔事件字元串的處理。
難點:Android音頻設備的切換底層入口是alsa_default.cpp,目前看來需要在asound.conf定義好local CODEC和USB Audio的plug;還需要修改
alsa_default.cpp,最主要Android要知道USBAudio插上時打開
USB Audio的plug,
USB Audio拔下時打開local CODEC的plug。這樣一想,修改的幅度還是蠻大的。而且未能確定如果在播放的過程中,切換音頻設備是否有影響?如果alsa允許只是配置好asound.conf達到同樣的目的,那就好辦了,可惜目前找不困昌到這方面的資料,應該沒有這個便利了。
進展:2011/9/19:按照以上難點分析,大致完成了整個Android框架層的代碼汪盯扒和ALSA配置文件,基本實現了USB Audio熱插拔時的音頻設備切換。但有個很大的問題:在播放時切換音頻設備會導致AudioFlinger服務crash(之前做2G通話時也遇到這個問題,用其他辦法規避了)。看來在切換音頻設備時,應該停止播放;等切換完成後,再恢復播放。