LinuxQuestions.org
Register a domain and help support LQ
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices



Reply
 
Search this Thread
Old 05-04-2005, 10:35 AM   #1
buckles
LQ Newbie
 
Registered: Jun 2003
Posts: 7

Rep: Reputation: 0
Problem using 'read' system call


Hello, all. Here is a snippet of kernel space code written to test read/write of an rs485 interface board. Ports 1 & 2 are connected via a loopback cable. System is Pentium 4 PC running RedHat 7.3
__________________________________________

unsigned char tempChar, buf[255];

...

fs = get_fs();
set_fs(get_ds());

if((fd_ttyS4 = open("/dev/ttyS4", O_RDWR | O_NOCTTY, 0)) < 0)
{
exit(1);
}

if((fd_ttyS5 = open("/dev/ttyS5", O_RDWR | O_NDELAY | O_NONBLOCK , 0)) < 0)
{
exit(1);
}

write(fd_ttyS5,&tempChar, 1)
read(fd_ttyS4,buf,1)

...

______________________________________

Seems simple. The loopback works fine when tempChar is initialized to a value between 0 and 0x7f. But when tempChar is 0x80 or greater, the subsequent read hangs forever. I am new to linux, so maybe I am missing something simple??? Thank you for any help you may provide.

Also, here is how I set the port attributes:

newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 1;

Last edited by buckles; 05-04-2005 at 02:37 PM.
 
Old 05-04-2005, 04:51 PM   #2
buckles
LQ Newbie
 
Registered: Jun 2003
Posts: 7

Original Poster
Rep: Reputation: 0
Here is another piece of info:

The same code works fine when executed from userspace. Any char value gets successfully read back, even greater than 0x7f. Its just when executed from a kernel program that the read hangs. As you may already know, in order to execute a system call from kernelspace, the following steps have to be taken:

1. the directive __KERNEL_SYSCALLS__ must be included in the source file
2. set_fs(), get_fs(), get_ds() must be used appropriately to resolve any kernel/user addressing incompatibilities.

Also noticed that the read()/write() definitions in /usr/include/unistd.h (userspace) and /usr/src/linux/include/asm/unistd.h (kernelspace) differ slightly between files. One takes a 'void *' as the 2nd parameter, while the other takes a 'char *', or a 'const char *'. These definitions are included via the __KERNEL_SYSCALLS__ directive. Maybe this is why I can use values less than 0x7f, as well as any character string (since the highest ASCII value of any character is 0x7F) with successful results.
 
Old 05-05-2005, 12:19 AM   #3
foo_bar_foo
Senior Member
 
Registered: Jun 2004
Posts: 2,553

Rep: Reputation: 51
i'm confused -- the device dev/ttyS4 and dev/ttyS5 already have kernel level drivers or they wouldn't be in /dev
the device files in dev are the mechanism that user space programs use to communicate with the kernel space drivers and then the drivers communicate with the hardware.

a kernel level driver for a char device implements read and write system calls for user space programs doesn't use ones presented by another driver.
 
Old 05-05-2005, 02:22 PM   #4
buckles
LQ Newbie
 
Registered: Jun 2003
Posts: 7

Original Poster
Rep: Reputation: 0
This code is a fragment of a separate driver that I wrote for a proprietary hardware interface card (not the RS485 card). The code is part of a driver, hence, it resides in kernel space. But you are correct, in that the standard Linux serial drivers are primarily used (/dev/ttyS[4..7]).

Another thing I tried is to pass a ‘unsigned int *’ into the 2nd parameter of write() & read(), which normally should be valid (as read/write accepts a ‘void *’), and I got a compile time warning related to “incompatible types”

I guess my question is: Should the usage of the read()/write() system calls be different when used in userspace, as opposed to kernel space??
 
Old 05-06-2005, 01:06 AM   #5
foo_bar_foo
Senior Member
 
Registered: Jun 2004
Posts: 2,553

Rep: Reputation: 51
ok i get it i wil try to answer even though my knowledge is very limited and some of what say will no doubt be wrong and forgive as i go over what's already obvious.
first i'm not so sure you can use the read from <asm/unistd.h> directly..
some of the kernels internal implementations of things involve passed arguments from other interfaces.. sometimes you can use them on one archetecture and not the other.
the best thing to do from within the kernel would be to use sys_read from fs/read_write.c
because that's actually the kernel side read but for ix86 you can't and i might be wrong but sys_read is what calls /asm/unistd.h
sys_read calls vfs_read() which uses
Code:
if (file->f_op->read)
				ret = file->f_op->read(file, buf, count, pos);
and i think that's what you ought to be doing if you don't want to use libc
is implement read the same way
once you make a kernel side file object
from include/linux/fs.h: you get
Code:
struct file {
 struct list_head f_list;
 struct dentry  *f_dentry;
 struct vfsmount         *f_vfsmnt;
 struct file_operations *f_op;
 atomic_t  f_count;
 unsigned int   f_flags;
 mode_t   f_mode;
 int   f_error;
 loff_t   f_pos;
 struct fown_struct f_owner;
 unsigned int  f_uid, f_gid;
 struct file_ra_state f_ra;

 unsigned long  f_version;
 void   *f_security;

 /* needed for tty driver, and maybe others */
 void   *private_data;

#ifdef CONFIG_EPOLL
 /* Used by fs/eventpoll.c to link all the hooks to this file */
 struct list_head f_ep_links;
 spinlock_t  f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
 struct address_space *f_mapping;
};
normally a system call from user space is implemented by softirq 0x80
the call is held in an EAX register and the args are held in other registers
see __NR_read in <asm/unistd.h>
after the transition to kernel mode the processor saves all registers to proper function after checking if
EAX is out of range.
the sys_read function needs a file object looked up by the file descriptor passed from user space.

ok when you do it from kernel space
like you have accept you have to return at the end to user space
set_fs(fs); (you know that already i bet)
see you still have a user space call because like i said earlier thats what sys calls from glibc are designed to be even though you are doing it is kernel space so if you don't return to user space addressing to user space all pointers go false
_libc_read() a user space syscall then goes to kernel system_call() then to the kernel fs/read_write.c then to the read() in asm you were talking about (i think) so using glibc you are just being alowed to do system_call() a user space thing from within the kernel

so to try someting actually kernel level instead of _libc_read() so timing is not such an issue and you are not
push pop args across user to kernel space trying to make the transition between softirq and kernel space over and over making all those changes in cpu registers
try: (warning untested of course) and with no failure checking
perhaps further investigation will reveal how i have written this wrong as all my code is always wrong at first ! you should be able to get to this stuff from fs.h or that might be included in more external headers
Code:
fs = get_fs();
set_fs(get_ds()); 
file1 = fget(fd_ttyS4);
file2 = fget(fd_ttyS5);
file1->f_op->write(file1,&tempChar,0, &file1->f_pos )
file2->f_op->read(file2,buf,0, &file2->f_pos) 
set_fs(fs);

Last edited by foo_bar_foo; 05-06-2005 at 04:12 AM.
 
Old 05-06-2005, 07:43 AM   #6
jtshaw
Senior Member
 
Registered: Nov 2000
Location: Seattle, WA USA
Distribution: Ubuntu @ Home, RHEL @ Work
Posts: 3,892
Blog Entries: 1

Rep: Reputation: 66
Moved: This thread is more suitable in Programming and has been moved accordingly to help your thread/question get the exposure it deserves.
 
Old 05-10-2005, 12:45 PM   #7
buckles
LQ Newbie
 
Registered: Jun 2003
Posts: 7

Original Poster
Rep: Reputation: 0
foo_bar_foo...thanks so much for your help. I still haven't got the code working. I used the last code snippet you provided, tried some mods... the write seems to execute, but the read still blocks. Been doing a lot of reading, research and code inspection of header files. I've learned a lot, but still havent been able to pinpoint a specific reason for the read failure. Like you said, it seems like these functions were just not designed for inter-kernel use. I am currently splitting my time between researching this issue (looking for a kernel level read/write), and designing a userspace alternative task. I've spent so much time on this issue, and I think I may have to move on, bite the bullet, and implement the function in userspace. Thanks again for the help. If anybody has any ideas, I'm all ears.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
problem with adding a system call newcat Programming 17 04-08-2006 07:50 AM
I am trying implement sleep in read system call problem sbharsha Programming 1 09-19-2005 12:48 AM
Problem w/ 'read' system call - RH 7.3 buckles Linux - Newbie 3 05-07-2005 01:03 AM
difficulties with large files and system call read/write jwstric2 Programming 2 08-23-2004 12:42 AM
maximum value of count in read system call udayan Programming 2 06-13-2002 07:51 AM


All times are GMT -5. The time now is 05:33 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration