I’m trying to write my own device driver based on the code supplied in QNX documentation.
I interface with the driver rather unconventionally.
// open device
fd = open("/dev/mydriver",O_RDWR);
// sample write and read
status = write(fd, my_stuff, sizeof(my_stuff));
status = read(fd, my_stuff, sizeof(my_stuff));
For a write, my_stuff is a string that concatenates the address where I want to write with the actual data I want to write and also a bit telling whether or not this will be a byte or word read. The conversion is handled in the driver. This is the roughly same thing for read.
For the write, I’ve figured that I can recover my_stuff thru resmgr_msgread, do some ungraceful decoding, and everything works. However, I have not been able to figure out how to recover my_stuff in the read subroutine. resmgr_msgread doesn’t seem to work. I’ve looked through the ctp, msg, and ocb structures and haven’t found anything to help.
Does anyone out there have any suggestions. It would be very mch appreciated.
Indeed you can tell the read what exactly you are trying to read (address, byte, word). There are multiple solutions for this. I will list the one that comes to mind,
1 - Do a write prior to the read that will tell the read what to return (rating: ugly)
2 - Use ioctl() (rating; so so)
3 - Use lseek (that
s good for write as well) to indicate to the driver what address to use. That doesnt solve the problem of specifying byte/word size. You could have two paths: /dev/mydriver/byte and /dev/mydriver/word. Drawback is the operation isn
t atomic and results in extra context switch/messaging (costly if operation is done over network). (rating: valid candidate) 4 - This last proposition is, IMHO, very elegant and could work if you dont have lots of addresses to support. The trick is in the path space. The driver could present to the outside /dev/mydriver but the open callback is free to do what ever it wants with the rest of the path space. Imagine to following code
fd = open ( “/dev/mydriver/byte/0xc000”, O_RDONLY);
status = read( fd, data, sizeof(data) );
read() would return sizeof( data) from address 0xc0000 , in byte. You could even support a .bin or .txt extention to tell the driver to return the data in binary or ascii format. Note in the example above the open flags are set to O_RDONLY for extra security.
It`s not because ls /dev/mydriver returns only /dev/mydriver that the open cannot support virtual subdirectory. One extra posibility is once an address/format has been used it could be return through an ls command. Hence ls /dev/mydriver/ would tell you which address were accessed.
Of course if there is lots of addresses to operate from that can be a pain because there would be lots of file descriptor and open is a costly operation. You could combine the path trick with lseek to reduce the number of fd/open() and only used lseek here and there.
I would do it a different way though. I don
t like to split the write and read like this, it means extra messaging and context switches and if the operation is done over a network thats really gona hurt performace. Further more it becomes a non atomic operation. One option is to used ioctl, through wich you can send and receive data. One other option is to still do it with only read()