Linux device driver for a Smart Card IC module

2019-08-28 17:35发布

问题:

I have a smart card IC module, and I want to create a Linux device driver for it. This module is using SPI as the controlling line and has an interrupt line to indicate whether a card is ready. I know how to create a SPI device in Linux kernel and how to read data in the kernel when the interruption happens. But I have no idea on how to transfer the data to the user space (maybe need to create a device node for it), and how to give the user space a interruption to notify it. Does anyone have some suggestion?

回答1:

One way you can go about this is by creating a devfs entry and then having the interested process open that device and receive asynchronous notification from the device driver using fasync.

Once you have the notification in user space you can notify other interested processes by any means you deem fit.

I am writing a small trimmed down example illustrating this feature.

On the driver side

/* Appropriate headers */

static int myfasync(int fd, struct file *fp, int on);
static struct fasync_struct *fasyncQueue;

static struct file_operations fops =
{
     .open = charDriverOpen,
     .release = charDriverClose,
     .read = charDriverRead,
     .write = charDriverWrite,
     .unlocked_ioctl = charDriverCtrl,
     // This will be called when the FASYNC flag is set
     .fasync = myfasync,
};

static int __init charDriverEntry()
{
      // Appropriate init for the driver
      // Nothing specific needs to be done here with respect to
      // fasync feature.
 }

static int myfasync(int fd, struct file *fp, int on)
{
      // Register the process pointed to by fp to the list
      // of processes to be notified when any event occurs
      return fasync_helper(fd, fp, 1, &fasyncQueue);
}

// Now to the part where we want to notify the processes listed
// in fasyncQueue when something happens. Here in this example I had
// implemented the timer. Not getting in to the details of timer func
// here
static void send_signal_timerfn(unsigned long data)
{
       ...
       printk(KERN_INFO "timer expired \n");

       kill_fasync(&fasyncQueue, SIGIO, POLL_OUT);
       ...
}

On the user land process side

void my_notifier(int signo, siginfo_t *sigInfo, void *data)
{
        printf("Signal received from the driver expected %d got %d \n",SIGIO,signo);
}

int main()
{
       struct sigaction signalInfo;
       int flagInfo;

       signalInfo.sa_sigaction = my_notifier;
       signalInfo.sa_flags = SA_SIGINFO;
       sigemptyset(&signalInfo.sa_mask);

       sigaction(SIGIO, &signalInfo, NULL);


       int fp,i;
       fp = open("/dev/myCharDevice",O_RDWR);
       if (fp<0)
               printf("Failed to open\n");

       /*New we will own the device so that we can get the signal from the device*/
       // Own the process
       fcntl(fp, F_SETOWN, getpid());
       flagInfo = fcntl(fp, F_GETFL);
       // Set the FASYNC flag this triggers the fasync fops 
       fcntl(fp, F_SETFL, flagInfo|FASYNC);
       ...
}

Hope this clears things up. For more detailed reading I suggest you read this