[英]Linux Char device driver not working if build as external module but worked if build as against running kernel.But why?
[英]Linux kernel char driver write call is not working as expected
我正在嘗試使用字符驅動程序實現FIFO。 但是,在寫入設備時,它似乎不起作用。 它似乎並沒有結束循環。 任何幫助或鏈接表示贊賞。 我已經從許多來源獲得幫助,所以當前的代碼有些混亂,而實際情況並非如此。
static ssize_t dev_write(struct file *filp, const char *buff, size_t len, loff_t *off) {
int mode;
int ind;
ssize_t count = -ENOMEM;
printk(KERN_ALERT "to be written : %s\n", buff);
mode = iminor(filp->f_dentry->d_inode);
printk(KERN_ALERT "Device minor : %d\n", mode);
if ((mode == 1) || (mode ==3))
return -EINVAL;
if (mode == 0){
count = 0;
ind = 0;
if (buff[ind] == NULL) {
return -ENOMEM;
}
printk(KERN_ALERT "Write position1 : %d\n", writePos1);
while(ind<=len) { //loop untill we have something to writer
if (down_interruptible(&buffer1_e)) { //taking flag first isn't right because that won't allow other guyto give access to our turn.
printk(KERN_ALERT "buffer1 flag didn't work\t %d", buffer1_e.count);
return -ERESTARTSYS;
}
else {
if (down_interruptible(&flag1)){
up(&buffer1_e); //must because we couldn't write it properly
return -EINVAL;
}
else {
queue1[writePos1] = buff[ind];
printk(KERN_ALERT "Write %d %c\n",ind,queue1[writePos1]);
if (writePos1 == 9){
writePos1 = 0;
}
else
writePos1++;
count++;
}
up(&flag1);
}
up(&buffer1_f);
off += count;
ind++;
}
printk(KERN_ALERT "Write position1 now: %d\t and count%d\n", writePos1,count);
return count-1;
}
我只是編寫了自己的模塊,並且懷疑您的問題是調用dev_write的進程期望dev_write返回寫入的字節數。 如果您沒有返回正確的數字(我看到您正在返回count-1),則dev_write將被反復調用。
我發現dev_read是相似的-直到它返回0,該過程將反復調用它-期望有更多的字符要檢索(這很有意義)。
我已經編寫/修改了一個更加簡單的模塊,該模塊說明了如何將模塊用作字符緩沖區(對不起,編寫起來很倉促)。 它應該允許您向它回顯一個字符串,並在接收或讀取它時返回該字符串。 當您make run
時就可以證明這一點。 我相信您將能夠輕松地對其進行修改以使其成為FIFO。
對於崩潰的內核或其他問題,我不承擔任何責任,無論如何,您都應該使用VM。
很長,所以在我的github上:
git clone https://github.com/n-hutton/tempRepo
cd tempRepo
make
make run
最后,我更正了完整的代碼。 這是非常不成熟的,對於少數邏輯而言,這是不合邏輯的,但我仍然願意這樣做。 @Nathan Hutton在改進和使它起作用方面提供了很多幫助。 我為此感謝他。 盡管仍有很多問題,我仍然有一個主要的疑問,如果您可以在內核日志中跟蹤它,則每次使用(echo“ test” | cat> / dev / fifo0)寫入設備時,都會添加一個額外的換行符。要正確運行它,您還需要創建4個字符設備,它們的主要編號為240,次要編號為0、1、2、3。 mknod可以用作:“ mknod / dev / fifo(0,1,2,3)c 240(0,1,2,3)-m 777” //一次0,1,2,3和777可以修改粒度。 最后的工作代碼:
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/unistd.h>
#include <linux/time.h>
#include <linux/semaphore.h>
#define DEVNO 240
#define DEVNAME "fifo"
MODULE_LICENSE("GPL");
DECLARE_WAIT_QUEUE_HEAD(writing1);
//static short writeFlag1=0;
static DEFINE_SEMAPHORE(flag1);
static DEFINE_SEMAPHORE(flag2);
static struct semaphore buffer1_f;
static struct semaphore buffer2_f;
static struct semaphore buffer1_e;
static struct semaphore buffer2_e;
DECLARE_WAIT_QUEUE_HEAD(writing2);
//static short writeFlag2=0;
static char queue1[10]={0};
static short readPos1=0;
static short writePos1=0;
//static short qsize1=0;
static char queue2[10]={0};
static short readPos2=0;
static short writePos2=0;
//static short qsize2=0;
static int times=0;
static int dev_open(struct inode *,struct file *);
static int dev_rls(struct inode *,struct file *);
static ssize_t dev_read(struct file *,char *,size_t,loff_t *);
static ssize_t dev_write(struct file *,const char *,size_t,loff_t *);
static struct file_operations fops={
.read=dev_read,
.write=dev_write,
.open=dev_open,
.release=dev_rls,
};
int init_module(void){
unsigned int devno = 240;
char *devname = "fifo";
int t;
sema_init(&buffer1_f,0);
sema_init(&buffer2_f,0);
sema_init(&buffer1_e,10);
sema_init(&buffer2_e,10);
memset(queue1,0,10);
memset(queue2,0,10);
t=register_chrdev(devno,devname,&fops);
if(t<0) printk(KERN_ALERT "device reg failed. \n");
else printk(KERN_ALERT "Device registered. \n");
return t;
}
void cleanup_module(void) {
unregister_chrdev(240,"fifo");
printk(KERN_ALERT "Device has been removed");
}
static int dev_open(struct inode *inod, struct file *fil){
times++;
printk(KERN_ALERT "Device opened %d times\n",times);
return 0;
}
static ssize_t dev_read(struct file *filep, char *buff, size_t len, loff_t *off) {
int mode = iminor((filep->f_dentry->d_inode));
short count;
printk(KERN_ALERT "Device minor when read : %d\n", mode);
if ((mode == 0) || (mode ==2))
return -EINVAL;
else if (mode == 1){
count = 0;
printk(KERN_ALERT "Read position1 when read: %d\n", readPos1);
while(len) { //loop untill we have something to write or empty buffer
if (readPos1==writePos1){
printk(KERN_ALERT "Returning chars put to buffer: %d\n", count);
return count;
}
if (down_interruptible(&buffer1_f)) {
printk(KERN_ALERT "flag1 didn't work");
return -ERESTARTSYS;
}
else {
if (down_interruptible(&flag1)){
return -EINVAL;
}
else {
printk(KERN_ALERT "Read %c\n",queue1[readPos1]);
put_user(queue1[readPos1],buff++);
if (writePos1==-1) writePos1=readPos1;
if (readPos1 == 9) readPos1 = 0;
else readPos1++;
count++;
}
up(&flag1);
}
up(&buffer1_e);
}
printk(KERN_ALERT "Read position1 now: %d\t and count%d\n", readPos1,count);
return count;
}
else if (mode == 3){
count = 0;
printk(KERN_ALERT "Read position2 when read: %d\n", readPos2);
while(len) { //loop untill we have something to write or empty buffer
if (readPos2==writePos2){
printk(KERN_ALERT "Returning chars put to buffer: %d\n", count);
return count;
}
if (down_interruptible(&buffer2_f)) {
printk(KERN_ALERT "flag2 didn't work");
return -ERESTARTSYS;
}
else {
if (down_interruptible(&flag2)){
return -EINVAL;
}
else {
printk(KERN_ALERT "Read %c\n",queue2[readPos2]);
put_user(queue2[readPos2],buff++);
if (writePos2==-1) writePos2=readPos2;
if (readPos2 == 9) readPos2 = 0;
else readPos2++;
count++;
}
up(&flag2);
}
up(&buffer2_e);
}
printk(KERN_ALERT "Read position2 now: %d\t and count%d\n", readPos2,count);
return count;
}
else {
printk(KERN_ALERT "Not correct mode\n");
return -1;
}
}
static char Message[100] = "Initial message\n";
static ssize_t dev_write(struct file *filp, const char *buff, size_t len, loff_t *off) {
int mode;
int ind;
ssize_t count = -ENOMEM;
int i;
//Let's copy the message onto our stack so we can be clear what we are getting
for (i = 0; i < 99 && i < len; i++){
char getChar;
get_user(getChar, buff + i);
Message[i] = getChar;
}
Message[i] = '\0';
printk(KERN_ALERT "to be written : %s\n", Message);
mode = iminor(filp->f_dentry->d_inode);
printk(KERN_ALERT "Device minor : %d\n", mode);
if ((mode == 1) || (mode ==3))
return -EINVAL;
else if (mode == 0){
count = 0;
ind = 0;
if (( buff == NULL) || (*buff == 0)) {
return -ENOMEM;
}
printk(KERN_ALERT "Write position1 : %d\n", writePos1);
while(ind<len) { //loop untill we have something to writer
if (down_interruptible(&buffer1_e)) { //taking flag first isn't right because that won't allow other guyto give access to our turn.
printk(KERN_ALERT "buffer1 flag didn't work\t %d", buffer1_e.count);
return -ERESTARTSYS;
}
else {
if (down_interruptible(&flag1)){
up(&buffer1_e); //must because we couldn't write it properly
return -EINVAL;
}
else {
queue1[writePos1] = buff[ind];
printk(KERN_ALERT "Write ind:%d writepos:%d readpos;%d char:%c\tascii%d\n",ind,writePos1,readPos1,queue1[writePos1],(int)queue1[writePos1]);
if (readPos1==((writePos1+1)%10)) {
writePos1=-1;
}
else if (writePos1 == 9){
writePos1 = 0;
}
else
writePos1++;
count++;
}
printk(KERN_ALERT "writepos:%d",writePos1);
up(&flag1);
}
up(&buffer1_f);
off += count;
ind++;
}
printk(KERN_ALERT "Write position1 now: %d\t and count%d\n", writePos1,(int)count);
printk(KERN_ALERT "Note: our allowable buffer length was %d\n", (int)len);
return count;
}
else if (mode == 2){
count = 0;
ind = 0;
if (( buff == NULL) || (*buff == 0)) {
return -ENOMEM;
}
printk(KERN_ALERT "Write position2 : %d\n", writePos2);
while(ind<len) { //loop untill we have something to writer
if (down_interruptible(&buffer2_e)) { //taking flag first isn't right because that won't allow other guyto give access to our turn.
printk(KERN_ALERT "buffer2 flag didn't work\t %d", buffer2_e.count);
return -ERESTARTSYS;
}
else {
if (down_interruptible(&flag2)){
up(&buffer2_e); //must because we couldn't write it properly
return -EINVAL;
}
else {
queue2[writePos2] = buff[ind];
printk(KERN_ALERT "Write ind:%d writepos2:%d readpos2;%d char:%c\tascii%d\n",ind,writePos2,readPos2,queue2[writePos2],(int)queue2[writePos2]);
if (readPos2==((writePos2+1)%10)) {
writePos2=-1;
}
else if (writePos2 == 9){
writePos2 = 0;
}
else
writePos2++;
count++;
}
printk(KERN_ALERT "writepos:%d",writePos2);
up(&flag2);
}
up(&buffer2_f);
off += count;
ind++;
}
printk(KERN_ALERT "Write position2 now: %d\t and count%d\n", writePos2,(int)count);
printk(KERN_ALERT "Note: our allowable buffer length was %d\n", (int)len);
return count;
}
else {
printk(KERN_ALERT "This meant wrong device minor accessed\n");
return -1;
}
}
static int dev_rls(struct inode *inod, struct file *fil) {
printk(KERN_ALERT "Device is closed\n");
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.