简体   繁体   中英

To write Linux driver in MCA 8000A

The software has been already written for Windows. I am thinking what is the good way to write it in Linux. Just directly in Linux or altering the Windows codes.

The case example is National Instruments' driver for MCA 8000A here which many have tried unsuccessfully write for Linux, for instance here , because of better embedding then and less hardware required for the application, ultimate target is Raspberry Pi here .

I started to write it by converting the Windows files to Linux but I am uncertain if this is the good way.

Authors with some variants of Linux drivers in MCA 8000A

MCA 8000A Linux Driver Plan for Raspberry Pi

The following codes are from the first link documented in the API.

Their Pmcatest.cpp

#include <windows.h>           // Change
#include <stdio.h>
#include "PmcaCom.h"
#include "PmcaErr.h"

static int g_port;
static int g_baudRate;
static int g_gain;
static int g_scale;
static PmcaDeviceType g_device;
static PmcaFlagsType g_flags;
static PmcaStatusType g_status;
static char chBuff[32];
static unsigned long buff[16384];
#define MAX_MEMORY 32768
#define printf0(format) printf(format); fflush(stdout)
#define printf1(format, item) printf(format, item); fflush(stdout)

// command line: test <com port> <baud rate> <device type> <start gain>
// device type 0 - AUTO DETECT, 1 - PMCA 8000, 2 - PMCA 8000A 
int main(int argc, char *argv[])
{       
    ...
}

MicroTime.cpp

#if !defined(AFX_MICROTIME_H__495147C7_F0B7_11D1_B62F_9CFF0CC10000__INCLUDED_)
#define AFX_MICROTIME_H__495147C7_F0B7_11D1_B62F_9CFF0CC10000__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

class MicroTimeType  
{
    LARGE_INTEGER m_startTime;
    ...
public:
    MicroTimeType();
    LARGE_INTEGER GetCounter();
    ...
};

#endif // !defined(AFX_MICROTIME_H__495147C7_F0B7_11D1_B62F_9CFF0CC10000__INCLUDED_)

Queue.cpp

#include "windows.h"
#include "Queue.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

QueueType::QueueType()
{
    ...
}

long QueueType::Put(QueueEntryType *entry)
{
    ...
}

QueueEntryType *QueueType::Get(void)
{
    ...
}

QueueEntryType *QueueType::LockedFind(long id)
{
   ...
}       

QueueEntryType *QueueType::Remove(long id)
{
   ...
}

Other codes where Windows configs

  • Pmcaex.cpp
  • Request.cpp

How can you write Linux driver in MCA 8000A?

Opening the source up I see there's a file called dataprot.pdf and MCA8000A USB Adapter Protocol.pdf , both explain in detail (a surprising amount at that) how the data protocols work across the serial (RS-232) and USB buses as well as the data structures RX'd/TX'd to the PC and the MCA; from dataprot.pdf : The PC acts always as a master while the MCA responds always as a slave. The PC port output signal RTS is used by the PC to indicate the direction of the data transfer. RTS = HIGH indicates data transfer from PC to MCA (mode SEND), while RTS = LOW sets the data transfer direction from MCA to the PC (mode RECEIVE). The MCA constantly monitors the PC RTS line and responds accordingly. The action of the PC depends on the selected mode: SEND or RECEIVE. The DTR and DSR signals are used to synchronize the data streams from/to MCA8000A. The PC acts always as a master while the MCA responds always as a slave. The PC port output signal RTS is used by the PC to indicate the direction of the data transfer. RTS = HIGH indicates data transfer from PC to MCA (mode SEND), while RTS = LOW sets the data transfer direction from MCA to the PC (mode RECEIVE). The MCA constantly monitors the PC RTS line and responds accordingly. The action of the PC depends on the selected mode: SEND or RECEIVE. The DTR and DSR signals are used to synchronize the data streams from/to MCA8000A.

Looking at the source itself, I don't see anything too terribly crazy to port; things like __declspec(dllimport/dllexport) can be ignored, WaitForSingleObject can be replaced with a pthread_mutex_t (assuming pthreads and user space modules, not a full blown kernel driver), as well there might be some issues using types like LARGE_INTEGER and BYTE as those can be Windows platform specific (32/64bit types) and you might have to replace them with a uint64_t or unsigned char , things like QueryPerformanceFrequency could be replaced with clock_gettime(CLOCK_MONOTONIC...) ... though looking deeper at the source, it doesn't seem to be doing anything more than opening a COM port to the device and ensuring the data is packed in the right structures for the user of the code to do "simple" stuff like Receive(BYTE* buffer) or WaitForDsrToggle ..

To be honest, you've got a serial comm device and the data protocol to which it spec's too; you don't need to go to the kernel, or even C or C++, a shell script and pipe redirection (or any serial program ) will accomplish a lot of the data read/writes for you (mind you if you adhere to the spec in the document). It does depend on your needs though; I used the shell script/pipe-redirect method to test the embedded device drivers I wrote (write the C kernel drivers, flash the device, boot it with my COM port connected and waiting to start bit-banging the device with my shell script) .. I wouldn't "ship" a shell script as a driver though (if you were looking to do more than simply communicate with the device).

Hope that can help.

For datatype conversions from Windows to Linux, add the following to your appropriate files, as discussed here :

#include <stdint.h>

typedef uint8_t BYTE;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef int64_t LONGLONG;

typedef union _LARGE_INTEGER {
  struct {
    DWORD LowPart;
    LONG  HighPart;
  };
  struct {
    DWORD LowPart;
    LONG  HighPart;
  } u;
  LONGLONG QuadPart;
} LARGE_INTEGER, *PLARGE_INTEGER;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM