This .c file is a device driver for DAQ card using linux OS. Is there a way of modifying this so it will work on windows OS?

The header file is also shown seperately at the end of the .c file.


/* pc30at
* =======
*
* Linux device driver for the pc30at data acqusition card.
*
* This board has 16 channels of 12-bit A-D, 2 channels of 12-bit D-A and
* 20-bit of digital I/O.
*
*
* This driver is intended for use as a kernel module which can be inserted into the linux 2.2 kernel during runtime. Code was ported from the old 2.0 kernel.
*
*
* ------------------------------------------------------------------------------
* /

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/wrapper.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/segment.h>
#include "pc30at.h" /* follows at end */

/* Define for verbose debugging support */
#undef PC30AT_DEBUG

/* Buffers to hold most recent conversion as either short integer or char array.
* Note we read unsigned short integers but write using signed short integers.
* Using short integers is important, because we assume that each integer is two
* characters (bytes) of the user buffer.
*/

static union
{
char byte[2];
unsigned short int integer;
}current_adc[16]; // Maximum A to D conversion

static union
{
char byte[2];
short int integer;
}current_dac[2]; // Maximum D to A conversion

/* Value returned from pc30at_open if driver opened successfully */
#define SUCCESS 0

/* Used to prevent concurent access into the same device */
static int Device_Open = 0;

/* pc30at_read function
*
* This is the read function for the pc30at card.
* The function is designed to read the number of channels set by num_in_chan on
* each iteration. The user program has to provide a character buffer array, which
* must be of size 2*num_in_chan, so that short (2 bit) integers can be put into it.
*/

static ssize_t pc30at_read (struct file *file, char *buf, size_t count, loff_t *ptr){
int num_in_chan = count/2; // Number of input channels used on the daq
char *p = buf; // Temporary pointer to the user buffer
int i; // Counter

#ifdef PC30AT_DEBUG
printk("pc30at read function called\n");
#endif

/* Set count equal to zero, which corresponds to no bytes read */
count=0;

/* Select first channel to start the conversion and put in an ioctl */
outb((unsigned char)(0x2+(0x10*0)),PC30AT_BASE+PORT_C30AT);

/* Main reading loop */
for(i=0;i<num_in_chan;i++){
// Set trigger to 1
outb((unsigned char)(0x3+(0x10*i)),PC30AT_BASE+PORT_C30AT);
// Set trigger to 0 to start conversion
outb((unsigned char)(0x2+(0x10*(i+1 % num_in_chan))),
PC30AT_BASE+PORT_C30AT);

/* Wait until conversion has finished */
while (((inb(PC30AT_BASE+PORT_B30AT))& (0x20))==0);

/* Read the converted data to the character buffer in two bytes */
current_adc[i].byte[0]=inb(PC30AT_BASE+PORT_A30AT);
current_adc[i].byte[1]=(inb(PC30AT_BASE+PORT_B30AT)&0x0f);
}

/* Put the values from the current array into the user character buffer */
for(i=0;i<num_in_chan;i++){
put_user(current_adc[i].byte[0],p++);
put_user(current_adc[i].byte[1],p++);
}
return count;
}

/* pc30at_write function
*
* This function reads data from a user buffer and writes it to the DA registers
* of the pc30at card. There are only two output channels on this card: 0 and 1.
* If only one channel is required this must be channel 0. The user buffer must
* be size 2 for one channel and 4 for two channels - NO OTHER VALUES WILL WORK.
* The DA registers should be initialised by writing zero to both output channels.
*/

static ssize_t pc30at_write(struct file *file, const char *buf, size_t count, loff_t *ptr){
int num_out_chan = count/2; // Number of output channels used on the daq
int i; // Counter

#ifdef PC30AT_DEBUG
printk("pc30at write function called\n");
#endif

/* Check that the user buffer is the correct length */
if(count !=2 && count != 4){
printk("Write function: Buffer must be size 2 for one output channel
or 4 for two output channels! ");
printk("buffer size is ");
return count= -1;
}

/* Set count equal to zero, which corresponds to no bytes written */
count=0;

/* Get the values from the user character buffer into the current array */
for(i=0;i<num_out_chan;i++){
current_dac[i].byte[0]=buf[2*i];
current_dac[i].byte[1]=buf[2*i+1];
count++;

#ifdef PC30AT_DEBUG
printk("Value from the buffer %d \n",current_dac[i].integer);
#endif
}

/* Send the values to the DA registers. Note, the output for the daq is in a
* 12 bit format, hence the shifting is required to fit the 2 byte (16 bit) buffer.
*/
outb((unsigned char)(current_dac[0].integer>>4),PC30AT_BASE+DAC1H_30AT);
outb((unsigned char)(current_dac[0].integer<<4 & 0xF0),
PC30AT_BASE+DAC1L_30AT);
outb((unsigned char)(current_dac[1].integer>>4),PC30AT_BASE+DAC2H_30AT);
outb((unsigned char)(current_dac[1].integer<<4 & 0xF0),
PC30AT_BASE+DAC2L_30AT);
return count;
}

/* pc30at_ioctl
*
* This function implements ioctls for the pc30at board.
*/

static int pc30at_ioctl(struct inode *inode, struct file *filp,
unsigned int iocmd, unsigned long ioarg) {
switch (iocmd) {
default:
return -ENOTTY;
break;
}
}

/* pc30at_open function
*
* This function opens the pc30at device driver from the user code.
*/

static int pc30at_open(struct inode *inode, struct file *filp) {

#ifdef PC30AT_DEBUG
printk("pc30at open function called\n");
#endif

/* Two processes cannot be talked to at the same time */
if (Device_Open)
return -EBUSY;

Device_Open++;
MOD_INC_USE_COUNT; // Macro to indicate module is being used
return SUCCESS;
}

/* pc30at_close function
*
* This function closes the pc30at device driver from the user code.
*/

static int pc30at_close(struct inode *inode, struct file *filp) {

#ifdef PC30AT_DEBUG
printk("pc30at close function called\n");
#endif

/* Ready for our next caller */
Device_Open --;
MOD_DEC_USE_COUNT; // Macro to indicate module is being used
return SUCCESS;
}

/* pc30at_fops
*
* This is the file operations structure for the pc30at driver. This structure
* is 'registered' by the register_chrdev routine which tells the kernel which
* fops are possible for this driver.
*/

static struct file_operations pc30at_fops = {
NULL, // Seek
pc30at_read,
pc30at_write,
NULL, // readdir
NULL, // Select
pc30at_ioctl, // ioctl
NULL, // mmap
pc30at_open,
NULL, // Flush
pc30at_close // Close
};

/* init_module function
*
* This function initialises the kernel module and registers the driver with the
* kernel. In addition it sets the pc30at card to 'default' settings.
*/

int init_module() {

int ret_val,ii;

/* Register the character device */
ret_val = module_register_chrdev(PC30AT_MAJOR,DEVICE_NAME,&p c30at_fops);

/* Negative values signify an error */
if (ret_val < 0) {
printk("Sorry, registering the character device failed ");
return ret_val;
}

/* Inform user of succesfully insertion */
printk("Inserting the kernel module has been completed succesfully.\n");
printk("The major device number is %d.\n", PC30AT_MAJOR);
printk("The base number (in HEX) is %d.\n", PC30AT_BASE);

/* Send the control word to the daq of 0x92, which sets ports A and B as input and
* port C as output.
*/
outb(0x92,PC30AT_BASE+CONTROL30AT);

/* Check that the card is there. First, start a conversion - for this daq, conversion
* is started with a downward edge trigger. The three commands below corresond to 010
* or _-_ so there is a downward edge between the last two and conversion is triggered.
*/
outb(0x2,PC30AT_BASE+PORT_C30AT);
outb(0x3,PC30AT_BASE+PORT_C30AT);
outb(0x2,PC30AT_BASE+PORT_C30AT);

/* Wait for the end of conversion. If no end, return an error */
ii=0;
while ((((inb(PC30AT_BASE+PORT_B30AT))& (0x20))==0)&&(ii<30000)) {
ii++;
if (ii>=30000) return -1;
}

#ifdef PC30AT_DEBUG
printk("Counter returned %d\n",ii);
printk("pc30at registers have initial setting\n");
#endif

return 0;
}

/* cleanup_module function
*
* This function removes the module from the kernel.
*/

void cleanup_module() {

int ret;

/* Unregister the device */
ret = module_unregister_chrdev(PC30AT_MAJOR, DEVICE_NAME);

/* If there's an error, report it */
if (ret < 0)
printk("Error in module_unregister_chrdev");
}




/* HEADER FILE
* This is an edited version of:
* ----------------------------------------
* das1200.h, M. Welsh ([email protected])
* Definitions for Linux DAS-1200 kernel module.
*
*/

#ifndef _LINUX_PC30AT_H
#define _LINUX_PC30AT_H

#include <linux/ioctl.h>

/* Define the following for your system */
#define PC30AT_MAJOR 126 /* Device major number */
#define PC30AT_BASE 0x720 /* I/O base address of card */
/*#define PC30AT_IRQ 5 */ /* IRQ of card */

/* _IOR means that we're creating an ioctl command number for passing
* information from a user process to the kernel module.
*
* The first arguments, MAJOR_NUM, is the major device number we're using.
*
* The second argument is the number of the command (there could be
* several with different meanings).
*
* The third argument is the type we want to get from the process to the
* kernel.
*/
/* Define count ioctl */
/*#define PC30AT_COUNT _IOW(PC30AT_MAJOR, 1, unsigned char)*/

/* The name for our device, as it will appear in /proc/devices */
#define DEVICE_NAME "PC30AT_dev"

/* Port settings */
#define PORT_A30AT 0x0
#define PORT_B30AT 0x1
#define PORT_C30AT 0x2
#define CONTROL30AT 0x3
#define DAC1H_30AT 0xD
#define DAC1L_30AT 0xC
#define DAC2H_30AT 0x11
#define DAC2L_30AT 0x10
#define USER_AAT 0x8
#define USER_BAT 0x9
#define USER_CONTROLAT 0xB
#define CONTROLWORDAT 0x07
#define COUNTER0AT 0x04

#endif /* _LINUX_PC30AT_H */