How to call compat_ioctl or unlocked_ioctl? - linux-device-driver

I'm trying to implement a driver for RTC (Real Time Clock). I used ioctl function in kernel 2.6.32. It worked fine. But when I run same driver in kernel 3.13.0, it gave an error ‘struct file_operations’ has no member named ‘ioctl’
when I changed ioctl to unlocked_ioctl and compat_ioctl, compiled and moduled inserted.
But calling ioctl in user application not invoking ioctl function in module. What function I have to use in user application to invoke compat_ioctl or unlocked_ioctl?

Check with arguments in driver
define structure file operation Definition like
static struct file_operations query_fops =
{
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
.ioctl = my_ioctl
#else
.unlocked_ioctl = my_ioctl
#endif
};
Define ioctl like
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35))
static int my_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg)
#else
static long my_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
#endif
{
switch(cmd){
....................................
...................................
}
}
and application level
No need to do any modification you can follow the basic rule for ioctl at application level.

Related

Function was not declared in the scope

I do not know why my program throws me error that I do not have defined functions even though I have them in the program. This happened after adding the code INA219 monitor;
My code:
#include "BNO055_ESP32.h"
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <INA219.h>
#define SHUNT_MAX_V 0.02 /* Rated max for our shunt is 75mv for 50 A current:
we will mesure only up to 20A so max is about 75mV*20/50 lets put some more*/
#define BUS_MAX_V 5 /* with 12v lead acid battery this should be enough*/
#define MAX_CURRENT 5 /* In our case this is enaugh even shunt is capable to 50 A*/
#define SHUNT_R 0.1 /* Shunt resistor in ohm */
#define SERVICE_UUID "6E40180D-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID "6E402A37-B5A3-F393-E0A9-E50E24DCCA9E"
// BLE variables
bool deviceConnected = false;
BLECharacteristic *pCharacteristic;
INA219 monitor;
void setup() {
Wire.begin(21, 22, 400000);
Serial.begin(115200); //opens serial terminal
monitor.begin();
monitor.configure(INA219::RANGE_16V, INA219::GAIN_1_40MV, INA219::ADC_16SAMP , INA219::ADC_16SAMP , INA219::CONT_SH_BUS);
monitor.calibrate(SHUNT_R, SHUNT_MAX_V, BUS_MAX_V, MAX_CURRENT);
BLEDevice::init("SMART HELMET");
//----------BLE INITIALIZATION-------------
// Create the BLE Server
BLEServer *pServer = BLEDevice::createServer();
}
void loop() {
readQuatData(BNO055_quatCount);
// Calculate the quaternion values
BNO055_quat[0] = (float)(BNO055_quatCount[0]) / 16384.;
BNO055_quat[1] = (float)(BNO055_quatCount[1]) / 16384.;
BNO055_quat[2] = (float)(BNO055_quatCount[2]) / 16384.;
BNO055_quat[3] = (float)(BNO055_quatCount[3]) / 16384.;
pCharacteristic->setValue((uint8_t*)BNO055_quat, 16);
pCharacteristic->notify(); // Send the value to the app!
}
void readQuatData(int16_t * destination)
{
uint8_t rawData[8]; // x/y/z gyro register data stored here
readBytes(BNO055_ADDRESS, BNO055_QUA_DATA_W_LSB, 8, &rawData[0]); // Read the six raw data registers sequentially into data array
destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ; // Turn the MSB and LSB into a signed 16-bit value
destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ;
destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
destination[3] = ((int16_t)rawData[7] << 8) | rawData[6] ;
}
Error I am getting:
C:\Users\Boris\Documents\Arduino\pokus_BNO055_ESP32\BNO_jedna_charka\BNO_jedna_charka.ino: In function 'void loop()':
BNO_jedna_charka:216:36: error: 'readQuatData' was not declared in this scope
readQuatData(BNO055_quatCount);
^
C:\Users\Boris\Documents\Arduino\pokus_BNO055_ESP32\BNO_jedna_charka\BNO_jedna_charka.ino: In function 'void readQuatData(int16_t*)':
BNO_jedna_charka:282:66: error: 'readBytes' was not declared in this scope
readBytes(BNO055_ADDRESS, BNO055_QUA_DATA_W_LSB, 8, &rawData[0]); // Read the six raw data registers sequentially into data array
^
C:\Users\Boris\Documents\Arduino\pokus_BNO055_ESP32\BNO_jedna_charka\BNO_jedna_charka.ino: In function 'bool initBNO055()':
BNO_jedna_charka:346:64: error: 'writeByte' was not declared in this scope
writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, BNO055_CONFIGMODE );
^
C:\Users\Boris\Documents\Arduino\pokus_BNO055_ESP32\BNO_jedna_charka\BNO_jedna_charka.ino: In function 'void accelgyroCalBNO055(float*, float*)':
BNO_jedna_charka:390:49: error: 'writeByte' was not declared in this scope
writeByte(BNO055_ADDRESS, BNO055_PAGE_ID, 0x00);
^
BNO_jedna_charka:401:65: error: 'readBytes' was not declared in this scope
readBytes(BNO055_ADDRESS, BNO055_ACC_DATA_X_LSB, 6, &data[0]); // Read the six raw data registers into data array
^
BNO_jedna_charka:430:65: error: 'readBytes' was not declared in this scope
readBytes(BNO055_ADDRESS, BNO055_GYR_DATA_X_LSB, 6, &data[0]); // Read the six raw data registers into data array
^
C:\Users\Boris\Documents\Arduino\pokus_BNO055_ESP32\BNO_jedna_charka\BNO_jedna_charka.ino: In function 'void magCalBNO055(float*)':
BNO_jedna_charka:530:64: error: 'writeByte' was not declared in this scope
writeByte(BNO055_ADDRESS, BNO055_OPR_MODE, BNO055_CONFIGMODE );
^
exit status 1
'readQuatData' was not declared in this scope
C:\Users\Boris\Documents\Arduino\ina219_pokus_stackoverflow\ina219_pokus_stackoverflow.ino: In function 'void loop()':
ina219_pokus_stackoverflow:45:32: error: 'readQuatData' was not declared in this scope
readQuatData(BNO055_quatCount);
^
C:\Users\Boris\Documents\Arduino\ina219_pokus_stackoverflow\ina219_pokus_stackoverflow.ino: In function 'void readQuatData(int16_t*)':
ina219_pokus_stackoverflow:63:66: error: 'readBytes' was not declared in this scope
readBytes(BNO055_ADDRESS, BNO055_QUA_DATA_W_LSB, 8, &rawData[0]); // Read the six raw data registers sequentially into data array
^
exit status 1
'readQuatData' was not declared in this scope
Thanks for any help.
Boris
In C and C++ you have to declare functions before you call them.
You can either do that by defining the function like you did here:
void readQuatData(int16_t * destination)
{
uint8_t rawData[8]; // x/y/z gyro register data stored here
readBytes(BNO055_ADDRESS, BNO055_QUA_DATA_W_LSB, 8, &rawData[0]); // Read the six raw data registers sequentially into data array
destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ; // Turn the MSB and LSB into a signed 16-bit value
destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ;
destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ;
destination[3] = ((int16_t)rawData[7] << 8) | rawData[6] ;
}
Or you can do it by using a function declaration like this:
void readQuatData(int16_t * destination);
You're calling readQuatData() before you declare it, so you're getting this error.
You can either move your definition of the function before the places that you use it, or you can declare it before you use it, like so:
INA219 monitor;
void readQuatData(int16_t * destination);
void setup() {
I placed it before the call to setup() as declaring everything you need to declare at the start of the file, before the code, is usually cleaner and more maintainable than scattering declarations throughout the code.
You'll need to do this for writeByte() and readBytes(). These seem to be missing from the code you shared, so you're on your own with them, but you'd do the same sort of thing - either define them before you use them, or add a declaration for them before you use them.

How to change value of module_param parameter in the device driver?

I wrote a simple program for taking a value through command line into my driver. I used module_param() for this and gave permission argument, i.e third arg of module_param(), as S_IWUSR.
This I guess would allow user to modify the value of that parameter once driver is loaded in the kernel. I tried to modify the value of that parameter by:
echo 1 > /sys/module/ghost/parameters/num
But this shows me Permission denied error every time I try to do this, even when I execute the command with sudo. I also tried changing permission in module_param() to 0770 but still was not able to change the parameter value. Is there a way to change the value of parameter passed while inserting the driver ? Why does the above command shows permission denied, even if I run as sudo ?
After the answer of #Ian Abott I am to change the value of the parameter. Now I tried to define a callback function to notify me any changes in the value of that parameter while my driver is loaded. Here is the code
#include"headers.h"
#include"declarations.h"
static int my_set(const char *val, const struct kernel_param *kp)
{
int n = 0, ret;
ret = kstrtoint(val,10,&n); // Kernel function to convert string to integer
if (ret !=0 || n > 10) {
return -EINVAL;
}
printk(KERN_ALERT "my-set function running\n");
return param_set_int(val,kp);
}
static const struct kernel_param_ops param_ops = {
.set = my_set,
.get = param_get_int,
};
module_param(num,int,0600);
static char *name = "hello";
module_param(name,charp,0770);
static int __init init_func(void)
{
int i;
module_param_cb(callBack, &param_ops, &num, 0770);
printk(KERN_INFO "Value of num is %d\n",num);
for( i=0; i<num; i++)
{
printk(KERN_INFO "%s\n", name);
}
return 0;
}
static void __exit exit_func(void)
{
printk(KERN_INFO "Value of num is %d\n",num);
printk(KERN_ALERT "Module removed successfully\n");
}
module_init(init_func);
module_exit(exit_func);
But it doesn't seem to work because my_set function never runs, even if I change the value. My doubt is
1) Is this correct way to implement callback function for the parameter?
2) What is significance of first argument to the function module_param_cb?

TMS320F2812 FatFs f_write returns FR_DISK_ERR

I have problem with an SD card. I'm using the FatFs library ver R0.10b to access the SD card.
My code:
// .... //
FATFS fatfs;
FIL plik;
FRESULT fresult,res1,res2,res3,res4,res5;
UINT zapisanych_bajtow = 0 , br;
UINT zapianie_bajtow = 0;
char * buffor = "123456789abcdef\r\n";
unsigned short int i;
void main(void) {
// ... //
res1 = f_mount(0,&fatfs); // returns FA_OK
res2 = f_open( &plik, "f721.txt", FA_OPEN_ALWAYS | FA_WRITE ); // returns FA_OK
if( res2 == FR_OK )
{
res3 = f_write( &plik, ( const void * ) buffor, 17, &zapisanych_bajtow ); // returns FR_DISK_ERR
}
res4 = f_close( &plik );// returns FR_DISK_ERR
for(;;)
{
}
}
Any idea what might be wrong?
I had similar error with just one difference. I tried to write 4096bytes with f_write function at once. And it always returned FR_DISK_ERR.
And this was caused because I tried to write more then is size of IO buffer in FIL structure in FatFS (defined in ff.h).
typedef struct {
FATFS* fs; /* Pointer to the related file system object (**do not change order**) */
WORD id; /* Owner file system mount ID (**do not change order**) */
BYTE flag; /* Status flags */
BYTE err; /* Abort flag (error code) */
DWORD fptr; /* File read/write pointer (Zeroed on file open) */
DWORD fsize; /* File size */
DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */
DWORD dir_sect; /* Sector number containing the directory entry */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
BYTE buf[_MAX_SS]; /* File private data read/write window */
} FIL;
The last array buf[_MAX_SS] is the file IO buffer. But _MAX_SS is user defined parameter (defined in ff.h) so you can decrease the amount of bytes written at once or eventually change the _MAX_SS value.
I know this is not your case because you only write 17 bytes at once, but this can be helpful for others.
It's few years when I finished with TMS but maybe it will help you:
FA_OPEN_ALWAYS Opens the file if it is existing. If not, a new file is created.
To append data to the file, use f_lseek() function after file open in this method.
If file does not exists use:
FA_CREATE_NEW Creates a new file. The function fails
with FR_EXIST if the file is existing.
I had the same issue with implementation of Chan FatFs on MSP430- always received FR_DISK_ERR result on calling disk_write().
My reason of the issue was the following:
operation failed on xmit_datablock() call, it returned 0.
xmit_datablock() failed because of xmit_spi_multi() failed.
xmit_spi_multi() failed because it was not enough to just transmit bytes from buffer.
It was necessary to read from RXBUF after every write.
Here it is how it looks after the issue was fixed:
/* Block SPI transfers */
static void xmit_spi_multi (
const BYTE* buff, /* Data to be sent */
UINT cnt /* Number of bytes to send */
)
{
do {
volatile char x;
UCA1TXBUF= *buff++; while(! (UCA1IFG & UCRXIFG)) ; x = UCA1RXBUF;
UCA1TXBUF= *buff++; while(! (UCA1IFG & UCRXIFG)) ; x = UCA1RXBUF;
} while (cnt -= 2);
}
Before fixing the issue there was no read from UCA1RXBUF following every write to UCA1TXBUF.
After fixing xmit_spi_multi() my issue with FR_DISK_ERR in disk_write() was solved.

How to add a built-in module to a C-Python API after Py_Initialize?

I have a module defined in my C code like so:
static struct PyModuleDef module_def = {
PyModuleDef_HEAD_INIT,
"the_module_name", /* m_name */
module_documentation, /* m_doc */
//....
};
and a function to initialize it:
PyMODINIT_FUNC init_the_module(void)
{
PyObject *mod, *submodule;
PyObject *sys_modules = PyThreadState_GET()->interp->modules;
mod = PyModule_Create(&module_def);
PyModule_AddObject(mod, "some_submodule", (submodule = init_the_submodule()));
PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
Py_INCREF(submodule);
// more submodules..
return mod;
}
The application that I am embedding python into is quite big and I can not change the workflow much. At this point Py_Initialize has already been called, so I can not call PyImport_ExtendInittabor PyImport_AppendInittab .
How can I create and add the module to the system modules?
Maybe I can manipulate the modules dictionary directly? Like so:
PyObject *modules, *the_module;
modules = PyImport_GetModuleDict();
PyDict_SetItemString(modules, "the_module_name", init_the_module());
the_module = PyDict_GetItemString(modules, "the_module_name"); //this is getting something back
std::cout << PyDict_Size(the_module) << std::endl; // this prints -1
The easiest way to handle this is to statically initialize your statically-linked modules by directly calling initspam() after the call to Py_Initialize() or PyMac_Initialize():
int main(int argc, char **argv)
{
/* Pass argv[0] to the Python interpreter */
Py_SetProgramName(argv[0]);
/* Initialize the Python interpreter. Required. */
Py_Initialize();
/* Add a static module */
initspam();
An example may be found in the file Demo/embed/demo.c in the Python source distribution.

Creating Threaded callbacks in XS

EDIT: I have created a ticket for this which has data on an alternative to this way of doing things.
I have updated the code in an attempt to use MY_CXT's callback as gcxt was not storing across threads. However this segfaults at ENTER.
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifndef aTHX_
#define aTHX_
#endif
#ifdef USE_THREADS
#define HAVE_TLS_CONTEXT
#endif
/* For windows */
#ifndef SDL_PERL_DEFINES_H
#define SDL_PERL_DEFINES_H
#ifdef HAVE_TLS_CONTEXT
PerlInterpreter *parent_perl = NULL;
extern PerlInterpreter *parent_perl;
#define GET_TLS_CONTEXT parent_perl = PERL_GET_CONTEXT;
#define ENTER_TLS_CONTEXT \
PerlInterpreter *current_perl = PERL_GET_CONTEXT; \
PERL_SET_CONTEXT(parent_perl); { \
PerlInterpreter *my_perl = parent_perl;
#define LEAVE_TLS_CONTEXT \
} PERL_SET_CONTEXT(current_perl);
#else
#define GET_TLS_CONTEXT /* TLS context not enabled */
#define ENTER_TLS_CONTEXT /* TLS context not enabled */
#define LEAVE_TLS_CONTEXT /* TLS context not enabled */
#endif
#endif
#include <SDL.h>
#define MY_CXT_KEY "SDL::Time::_guts" XS_VERSION
typedef struct {
void* data;
SV* callback;
Uint32 retval;
} my_cxt_t;
static my_cxt_t gcxt;
START_MY_CXT
static Uint32 add_timer_cb ( Uint32 interval, void* param )
{
ENTER_TLS_CONTEXT
dMY_CXT;
dSP;
int back;
ENTER; //SEGFAULTS RIGHT HERE!
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(interval)));
PUTBACK;
if (0 != (back = call_sv(MY_CXT.callback,G_SCALAR))) {
SPAGAIN;
if (back != 1 ) Perl_croak (aTHX_ "Timer Callback failed!");
MY_CXT.retval = POPi;
} else {
Perl_croak(aTHX_ "Timer Callback failed!");
}
FREETMPS;
LEAVE;
LEAVE_TLS_CONTEXT
dMY_CXT;
return MY_CXT.retval;
}
MODULE = SDL::Time PACKAGE = SDL::Time PREFIX = time_
BOOT:
{
MY_CXT_INIT;
}
SDL_TimerID
time_add_timer ( interval, cmd )
Uint32 interval
void *cmd
PREINIT:
dMY_CXT;
CODE:
MY_CXT.callback=cmd;
gcxt = MY_CXT;
RETVAL = SDL_AddTimer(interval,add_timer_cb,(void *)cmd);
OUTPUT:
RETVAL
void
CLONE(...)
CODE:
MY_CXT_CLONE;
This segfaults as soon as I go into ENTER for the callback.
use SDL;
use SDL::Time;
SDL::init(SDL_INIT_TIMER);
my $time = 0;
SDL::Timer::add_timer(100, sub { $time++; return $_[0]} );
sleep(10);
print "Never Prints";
Output is
$
it should be
$ Never Prints
Quick comments:
Do not use Perl structs (SV, AV, HV, ...) outside of the context of a Perl interpreter object. I.e. do not use it as C-level static data. It will blow up in a threading context. Trust me, I've been there.
Check out the "Safely Storing Static Data in XS" section in the perlxs manpage.
Some of that stuff you're doing looks rather non-public from the point of view of the perlapi. I'm not quite certain, though.
$time needs to be a shared variable - otherwise perl works with separate copies of the variable.
My preferred way of handling this is storing the data in the PL_modglobal hash. It's automatically tied to the current interpreter.
We have found a solution to this using Perl interpreter threads and threads::shared. Please see these
Time.xs
Also here is an example of a script using this code.
TestTimer.pl