RE: writing integers to the char device driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Thanks a bunch, this is really cool!
willis

________________________________________
From: kernelnewbies-bounce@xxxxxxxxxxxx [kernelnewbies-bounce@xxxxxxxxxxxx] On Behalf Of Daniel Widyanto [daniel.widyanto@xxxxxxxxxxxx]
Sent: Friday, February 20, 2009 10:28 AM
To: Troy, Willis
Cc: kernelnewbies@xxxxxxxxxxxx
Subject: RE: writing integers to the char device driver

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 ecartis@xxxxxxxxxxxx
Please read the FAQ at http://kernelnewbies.org/FAQ��.n��������+%����w�j)p���{.n����z�ޖw�n'���q���b�������v��m�����Y�����


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux