Hi Willis,
To get EOF in the application program, you just need to return 0 at your
driver's read function. IMHO, I think that you can use IOCTL to do your
driver easily.
Like this:
------------------------------------------------
multi.h
#ifndef MULTI_H
#define MULTI_H
#include <linux/ioctl.h>
#define MAJOR_NUM 66
/*
* Set the values of parameters
*/
#define IOCTL_SET_VALUES _IOW(MAJOR_NUM, 0, unsigned int *)
/*
* Get the result value
*/
#define IOCTL_GET_VALUES _IOR(MAJOR_NUM, 1, unsigned int *)
#endif
------------------------------------------------
multi.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/ioport.h>
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <asm/io.h> /* inb, outb */
#include "multi.h" /* IOCTL cmds */
#define reg_off_1 0x00000004
#define reg_off_2 0x00000008
MODULE_LICENSE("Dual BSD/GPL");
static const unsigned phy_add = 0x75600000;
static const unsigned remapSize = 0x10000;
static unsigned virt_add;
//static u32 dummyArg[3];
//static u32 *virt_add = &dummyArg[0];
static int multi_ioctl(struct inode *inode, /* see include/linux/fs.h */
struct file *file, /* ditto */
unsigned int ioctl_num, /* number and param for
ioctl */
unsigned long ioctl_param);
static struct file_operations multi_fops = {
.ioctl = multi_ioctl
};
static int multi_major = MAJOR_NUM;
static int multi_init(void)
{
int result;
result = register_chrdev(multi_major, "multi", &multi_fops);
virt_add = (unsigned) ioremap(phy_add, remapSize);
//printk("Mapping %x to virtual address %x\n", phy_add, virt_add);
return result;
}
static void multi_exit(void)
{
iounmap((void *)virt_add);
unregister_chrdev(multi_major, "multi");
}
static int multi_ioctl(struct inode *inode, /* see include/linux/fs.h */
struct file *file, /* ditto */
unsigned int ioctl_num, /* number and param for
ioctl */
unsigned long ioctl_param)
{
u32 conv_to_num = 0;
u32 conv_to_num2 = 0;
u32 result = 0;
/*
* Switch according to the ioctl called
*/
switch (ioctl_num) {
case IOCTL_SET_VALUES:
/*
* Receive pointer to two u32 values
*/
copy_from_user(&conv_to_num, (u32 *)ioctl_param, 4);
copy_from_user(&conv_to_num2, ((u32 *)ioctl_param + 1), 4);
*(volatile u32*) virt_add = conv_to_num;
*(volatile u32*)(virt_add+reg_off_1) = conv_to_num2;
printk(KERN_DEBUG " conv_to_num = %x\n", conv_to_num);
printk(KERN_DEBUG " conv_to_num2 = %x\n", conv_to_num2);
break;
case IOCTL_GET_VALUES:
/*
* Receive pointer to user buffer to hold u32 value
*/
result = *(volatile u32*) (virt_add+reg_off_2);
copy_to_user((void *)ioctl_param, (void *)&result, sizeof(u32));
printk(KERN_DEBUG " result = %x\n", result);
break;
}
return 0;
}
module_init(multi_init);
module_exit(multi_exit);
------------------------------------------------
user_app.c
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <fcntl.h> /* open */
#include <unistd.h> /* exit */
#include <sys/ioctl.h> /* ioctl */
#include "multi.h"
/*
* Functions for the ioctl calls
*/
void ioctl_set_values(int file_desc, uint32_t *param)
{
int ret_val = ioctl(file_desc, IOCTL_SET_VALUES, param);
if (ret_val < 0) {
printf("ioctl_set_values failed:%d\n", ret_val);
exit(EXIT_FAILURE);
}
}
void ioctl_get_values(int file_desc, uint32_t *result)
{
/*
* Warning − this is dangerous because we don't tell
* the kernel how far it's allowed to write, so it
* might overflow the buffer. In a real production
* program, we would have used two ioctls − one to tell
* the kernel the buffer length and another to give
* it the buffer to fill
*/
int ret_val = ioctl(file_desc, IOCTL_GET_VALUES, result);
if (ret_val < 0) {
printf("ioctl_get_values failed:%d\n", ret_val);
exit(EXIT_FAILURE);
}
}
/*
* Main − Call the ioctl functions
*/
uint32_t u32_param[2];
uint32_t u32_result;
int main(int argc, char *argv[])
{
if (argc != 4) {
fprintf(stdout, "Usage: %s <dev file> <uint32_t 1> <uint32_t 2>\n",
argv[0]);
exit(EXIT_FAILURE);
}
int fd = open(argv[1], O_RDWR);
if (fd < 0) {
fprintf(stderr,"Error : %x",errno);
exit(EXIT_FAILURE);
}
u32_param[0] = atoi(argv[2]);
u32_param[1] = atoi(argv[3]);
fprintf(stdout, "First val: %d\n", u32_param[0]);
fprintf(stdout, "Second val: %d\n", u32_param[1]);
ioctl_set_values(fd, &u32_param[0]);
ioctl_get_values(fd, &u32_result);
fprintf(stdout, "Result: %d\n", u32_result);
close(fd);
exit(EXIT_SUCCESS);
}
------------------------------------------------
Hope that helps. Sorry, I'm a bit blind with C++.
Regards,
-daniel
On Thu, 2009-02-19 at 13:12 -0600, Troy, Willis wrote:
> Howdy Daniel,
>
> The peripheral is memory mapped. I probably could use a standalone C++
> program and not use a device driver, but the goal is to eventually make more
> robust peripherals in the future.
> My driver and my C++ program to access it are posted below, though I have
> figured out that I can open the device as a binary file and write u32s to it
> and have it be just fine, though I am still having problems reading from it.
> Is it possible to put an EOF marker in the read statement?
>
> My device Driver:
> --------------------------------------------------------------------------------------------------------------------------------------------------------------
> #include <linux/init.h>
> #include <linux/module.h>
> #include <linux/kernel.h>
> #include <linux/slab.h>
> #include <linux/fs.h>
> #include <linux/errno.h>
> #include <linux/types.h>
> #include <linux/proc_fs.h>
> #include <linux/fcntl.h> /* O_ACCMODE */
> #include <linux/ioport.h>
> #include <asm/system.h> /* cli(), *_flags */
> #include <asm/uaccess.h> /* copy_from/to_user */
> #include <asm/io.h> /* inb, outb */
>
> //#define BUF_LEN 80
> #define reg_off_1 0x00000004
> #define reg_off_2 0x00000008
>
>
> static char *Message_Ptr;
> static u32 conv_to_num;
> static u32 conv_to_num2;
>
> MODULE_LICENSE("Dual BSD/GPL");
>
> unsigned phy_add = 0x75600000;
> unsigned remapSize = 0x10000;
> unsigned virt_add;
>
> int multi_open(struct inode *inode, struct file *filp);
> int multi_release(struct inode *inode, struct file *filp);
> ssize_t multi_write(struct file *filp, char *buf, size_t count, loff_t
> *f_pos);
> ssize_t multi_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
>
> struct file_operations multi_fops = {
> read: multi_read,
> write: multi_write,
> open: multi_open,
> release: multi_release,
> };
>
> int multi_major=66;
>
> int multi_init(void)
> {
> int result;
> result = register_chrdev(multi_major, "multi", &multi_fops);
> virt_add = (unsigned) ioremap(phy_add, remapSize);
> //printk("Mapping %x to virtual address %x\n", phy_add, virt_add);
> Message_Ptr=kmalloc(11, GFP_KERNEL);
> return 0;
> }
>
> void multi_exit(void)
> {
> iounmap((void *)virt_add);
> unregister_chrdev(multi_major, "multi");
> kfree(Message_Ptr);
> }
>
> ssize_t multi_read(struct file *filp, char *buf,size_t count, loff_t *f_pos) {
> int bytes_read=0;
>
> if(*Message_Ptr==0)
> return 0;
> while (count && *Message_Ptr){
> put_user(*(Message_Ptr++), buf++);
> count--;
> bytes_read++;
> }
> return bytes_read;
> }
>
> ssize_t multi_write( struct file *filp, char *buf, size_t count, loff_t
> *f_pos) {
> copy_from_user(&conv_to_num, buf, 4);
> copy_from_user(&conv_to_num2, buf+4, 4);
>
> *(volatile u32*)virt_add=conv_to_num;
> *(volatile u32*)(virt_add+reg_off_1)=conv_to_num2;
> /*
> printk("First number is %u\n",*(volatile u32*) (virt_add));
> printk("Conv_to_num is %u\n",conv_to_num);
> printk("Second number is %u\n",*(volatile u32*) (virt_add+reg_off_1));
> printk("Conv_to_num2 is %u\n",conv_to_num2);
> printk("Solution is %u\n",*(volatile u32*)(virt_add+reg_off_2));
> */
> sprintf(Message_Ptr,"%u",*(volatile u32*) (virt_add+reg_off_2));
> return 8;
> }
> int multi_open(struct inode *inode, struct file *filp) {
> /* Success */
> return 0;
> }
>
> int multi_release(struct inode *inode, struct file *filp) {
> /* Success */
>
> return 0;
> }
>
> module_init(multi_init);
> module_exit(multi_exit);
> -------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> My C++ program
> ------------------------------------------------------------------------
> #include <iostream>
> #include <fstream>
>
> using namespace std;
>
>
> int main()
> {
> unsigned number, number2;
> char *product;
> long size;
> fstream infile;
> infile.open("/dev/multi",ios::out | ios::in | ios::binary);
> cout<<"Enter a number: "<<endl;
> cin>>number;
> cout<<"Enter another number: "<<endl;
> cin>>number2;
>
> infile.write((char*)&number,4);
> infile.write((char*)&number2,4);
> size=infile.seekg(ios::end);
> infile.seekg(ios::beg);
> infile.read(product, size);
> cout<<"The solution is : ";
>
> cout<<product;
>
> cout<<endl;
> infile.close();
> return 0;
> }
> ---------------------------------------------------------------------------
--
To unsubscribe from this list: send an email with
"unsubscribe kernelnewbies" to [email protected]
Please read the FAQ at http://kernelnewbies.org/FAQ