Thread: Linux OS to Windows OS code

  1. #1
    Registered User
    Join Date
    Feb 2003
    Posts
    8

    Linux OS to Windows OS code

    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 */

  2. #2
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    Best bet to start with is to check out the details of the windows driver model. Look at MSDN ,there is no finer reference for windows programming.
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  3. #3
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    Read this before posting code please.
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pthread and socket porting from Linux to Windows
    By mynickmynick in forum C Programming
    Replies: 2
    Last Post: 07-18-2008, 06:57 AM
  2. Moving Lapack++ dependent code to windows
    By confuted in forum C++ Programming
    Replies: 1
    Last Post: 10-16-2007, 10:47 AM
  3. GUI library that works on windows and linux?
    By Logan in forum C++ Programming
    Replies: 2
    Last Post: 04-28-2006, 08:40 PM
  4. Erm...so what DOES Linux do that Windows doesn't?
    By 7smurfs in forum Tech Board
    Replies: 19
    Last Post: 09-09-2005, 03:04 PM
  5. Linux? Windows Xp?
    By VooDoo in forum Linux Programming
    Replies: 15
    Last Post: 07-31-2002, 08:18 AM