Use unregister_chrdev_region in case registration failed - linux-device-driver

I am learning how to write kernel drivers, and I have a doubt about the proper
usage of the function unregister_chrdev_region.
Right now I have a simple test module with just the init and
exit functions:
static dev_t devn;
int __init my_dev_init(void)
{
devn = MKDEV(0,0);
if(alloc_chrdev_region(&devn,0,1,"my_dev") != 0)
{
return -EBUSY;
}
else
{
return 0;
}
}
void __exit my_dev_exit(void)
{
unregister_chrdev_region(devn,1);
}
My question: is it safe to call unregister_chrdev_region if the registration failed ? I would assume no, but pretty much all example code that I have seen calls unregister_chrdev_region no matter what happened during the initialization.

Registration rarely fails. If registration fails, init function fails, thus insmod command will not succeed in loading the kernel module i.e. test.ko and device node will not be created. So there is no question of unregistration (rmmod). If registration is successful then only we can unregister the driver i.e. unloading the kernel, removal of device node etc... using rmmod. If in init function registration is successful and some other API fails then need to add goto statements, jump to appropriate goto label to unregister and return the appropriate error value. Hope I have cleared your doubt :-)

Related

How to check the BLE communication is still OK before writing to a characteristic

I use 'flutter_blue_plus' package to handle BLE connectivity in my app.
What is the best way to make sure the BLE write to a characteristic is possible before actually doing it?
Here is what I do for for now:
void sendCommand(String command) async {
print("SDLTP: writing command [$command] thru BLE");
const maxRetries = 3
var retry = 0;
do {
try {
retry++;
await bleSdltpCommandCharacteristic.write(utf8.encode(command));
break;
} on PlatformException {
await Future.delayed(Duration(milliseconds: 100));
} catch (e) {
print("Could not write on characterisics: $e");
}
// 3 retries to have a failsafe and avoid potential infinite loop
// TODO: Check if we cannot have a 'real/decent' max retry...
} while (retry < maxRetries);
}
The correct way to check if a characteristic can be written is to write to the characteristic. Pre-flight checking would achieve nothing here. Even if a pre-flight passes, the subsequent write can still fail, so you need to handle that case anyway. Core Bluetooth already performs all possible pre-flight checks. If the CPeripheral is known to be disconnected, the .state value will be .disconnected and the CBCentralManagerDelegate method centralManager(_:didDisconnectPeripheral:error:) will have been called. Other than "write a value and receive a response," there is no other way to know that a device can be written to.
If a BLE write fails, it is unlikely that an immediate retry will succeed, so this tight retry loop is unlikely to be helpful. In any case, 100ms is too short of a timeout for a BLE write. (Looking over the Flutter docs, I don't see any evidence this is a blocking call, anyway, so I'm not sure this attempt at timeouts is doing anything.)
Typically the existing retry/timeout logic of CoreBluetooth is correct. Trying to short-circuit and replace it this way is just fighting the system and likely to cause more problems for the device when you stack writes.

B&R get drive serial number via MC_BR_GetHardwareInfo function block

I'm trying to retrieve the serial number from a drive using the MC_BR_GetHardwareInfo function block. Since the documentation lacks any kind of example code on this topic I'm getting nowhere.
Which information should I provide to the function block in order to get the desired serial number?
Below sample will crash in the PLC, probably because the function block requires certain pointers to be addressed:
MC_HARDWARE_INFO_REF hwinfo;
MC_BR_GetHardwareInfo(&hwinfo);
You are probably getting a page fault, because you provide the MC_BR_GetHardwareInfo function block (FUB) a wrong type, which leads to random behavior.
A function block is basically a function which requires a reference to a specific type as parameter. This type contains the actual in- and outputs which are used, internal state variables, etc. We need this, because of the synchronous execution of the code. This means unlike a function, you need to call a FUB until it is done.
Let's take a look to the help of the FUB:
Guid: 056444ea-2a15-4af6-a5ae-0675894b17d3
So the FUB needs a reference to the Axis object of which you want to know the HW info and an Execute command. It will give you some status bits, an error code and the actual data you want to have within the structure HardwareInfo of the type MC_HARDWARE_INFO_REF.
First we need to instantiate the FUB by create a variable of its type. We do this in the local *.var file of the task:
VAR
fbGetHwInfo : MC_BR_GetHardwareInfo := (0);
END_VAR
Then we call set the parameters of the FUB and call it, which might look like this:
void _CYCLIC ProgramCyclic(void)
{
//should be set by the application or in watch/monitor; now it only
//executes once
fbGetHwInfo.Execute = 1;
//reference to your axis object; when using a wizard the first axis
//will be gAxis01 on default
fbGetHwInfo.Axis = (UDINT)&gAxis01;
//call the FUB
MC_BR_GetHardwareInfo(&fbGetHwInfo);
if(fbGetHwInfo.Error == 1)
{
//TODO: errorhandling
}
else if(fbGetHwInfo.Done == 1)
{
//TODO use output
//fbGetHwInfo.HardwareInfo
}
}
typically you would do this in some statemachine. Also you probably have to wait until the network to the drive is initialized. You could check this with the MC_BR_ReadDriveStatus FUB. Just for testing it should be enough to wait for some seconds after reboot and set the Execute flag in monitor mode.

uvm register write is stuck and never return

I have some block of register along with corresponding register adaptor setup to translate into some bus protocol.
When I called the write method to one of my register, I could see the transaction going on, and driver complete its job, but write is stuck somewhere.
Please see excerpt of driver and sequence below:
// ...uvm driver
forever begin
seq_item_port.get_next_item(req);
$display("DEBUG A");
// ... do transaction
seq_item_port.item_done();
$display("DEBUG B");
end
// ... sequence
$display("START WRITE");
my_reg_block.my_reg1.write(
$display("DONE WRITE");
The result:
START WRITE
DEBUG A
DEBUG B
and then simulation stuck there - I never see DONE WRITE.
I am quite sure all the connect, set_sequencer has been made properly - otherwise my driver shouldn't see transaction in the first place. And this is pretty simple test - only doing that write.
Any idea why it is stuck in register write method eventhough the driver seems to have completed the transaction? I probably missed something.
In uvm_reg_map::do_bus_write(...) there's the following code snippet that handles the bus request for a register access:
bus_req.set_sequencer(sequencer);
rw.parent.start_item(bus_req,rw.prior);
if (rw.parent != null && i == 0)
rw.parent.mid_do(rw);
rw.parent.finish_item(bus_req);
bus_req.end_event.wait_on();
Notice the end_event.wait_on(). This event is normally triggered on a sequence item by the sequencer, once item_done() was called and finish_item() returns:
`ifndef UVM_DISABLE_AUTO_ITEM_RECORDING
sequencer.end_tr(item);
`endif
It's possible to turn this off using the define, which is what I guess is happening in your case.

QApplication::processEvents never returns

In my application I need to wait until external program (using QProcess) is finished. I want to keep the application responsible so blocking methods are unacceptable.
Also I need to disallow user input. I've tried to make QEventLoop and exec it with QEventLoop::ExcludeUserInputEvents flag, but as documentation says it only delays an event handling:
the events are not discarded; they will be delivered the next time processEvents() is called without the ExcludeUserInputEvents flag.
So I implemented simple event filter and install it on qApp (the idea is took from Qt Application: Simulating modal behaviour (enable/disable user input)). It works well, but sometimes QApplication::processEvents function never returns even if I specify the maximum timeout. Could anyone help me to understand for what reasons it periodically happens?
class UserInputEater : public QObject
{
public:
bool eventFilter(QObject *object, QEvent *event)
{
switch(event->type())
{
case QEvent::UpdateRequest:
case QEvent::UpdateLater:
case QEvent::Paint:
return QObject::eventFilter(object, event);
default:
return true;
}
}
};
-
UserInputEater eventEater;
qApp->installEventFilter(&eventEater);
QProcess prc;
prc.start("...");
while(!prc.waitForFinished(10))
{
if(qApp->hasPendingEvents())
{
// Sometimes it never returns from processEvents
qApp->processEvents(QEventLoop::AllEvents, 100);
}
}
qApp->removeEventFilter(&eventEater);
UPD: Seems like it depends of the timeout value for QProcess::waitForFinished.
I guess you are filtering some useful events (for example, QEvent::SockAct could be involved). Try to add some debug output and find out which event types you're actually filtering. Or it might be better to specify the black list of events you want to block instead of white list of events you want to allow. See this answer.
Also you shouldn't use return QObject::eventFilter(object, event);. You should use return false. All other event filters will be called automatically.
This solution however seems weird and unreasonable to me because you can just call setEnabled(false) for your top level widget to block user input, and then you can use QApplication::processEvents without any flags.

System call implementation in Pintos

I want to implement the already defined system calls in PintOS ( halt(), create()...etc defined in pintos/src/lib/user/syscall.c ). The current system call handler in pintos/src/userprog/syscall.c does not do anything. How do I make a process that makes system calls. Further I need to myself add a few system calls. How do I proceed in that too. But first I need to implement the existing system calls.
The default implementation in pintos terminates the calling process.
goto this link.There is explanation on where to modify the code to implement the system calls.
The "src/examples" directory contains a few sample user programs.
The "Makefile" in this directory compiles the provided examples, and you can edit it compile your own programs as well.
This program/process when run will inturn make a system call.
Use gdb to follow the execution of one such program a simple printf statement will eventually call write system call to STDOUT file.
The link given also has pointers on how to run pintos on gdb, my guess is you are using either bochs or qemu.In any case just run the gdb once with a simple hello world program running on pintos.
This will give u an idea of how the system call is made.
static void
syscall_handler (struct intr_frame *f)// UNUSED)
{
int *p=f->esp;
switch(*p)
case *p=SYS_CREATE // NUMBER # DEFINED
const char *name=*(p+1); //extract the filename
if(name==NULL||*name==NULL)
exit(-1);
off_t size=(int32_t)*(p+2);//extract file size
f->eax=filesys_create(name,size,_FILE); //call filesys_create
//eax will have the return value
}
This is pseudo code for sys_create .. all file system related system call are very trivial,
Filesys realted system calls like open read write close needs you to translate file to their corresponding fd (file descriptor). You need to add a file table for each process to keep track this, this can either be preprocess data or a global data.(UR choice),
case (*p==SYS_WRITE)
{
// printf("wite syscall\n");
char *buffer=*(p+2);
unsigned size=*(p+3);
int fd=*(p+1);
// getiing the fd of specified file
struct file *fil= thread_current()->fdtable[fd];/ my per thread fdtable
if(fd==1) goto here;
if(is_directory(fil->inode)){
exit(-1);
goto done;
}
here:
if(buffer>=PHYS_BASE)exit(-1);
if(fd<0||fd>=128){exit(-1);}
if(fd==0){exit(-1);} // writing to STDIN
if(fd==1) //writing to STDOUT
{
int a=(int)size;
while(a>=100)
{
putbuf(buffer,100);
buffer=buffer+100;
a-=100;
}
putbuf(buffer,a);
f->eax=(int)size;
}
else
if(thread_current()->fdtable[fd]==NULL)
{f->eax=-1;}
else
{
f->eax=file_write(thread_current()->fdtable[fd],buffer,(off_t)size);
}
done: ;
}//printf("write");} /* Write to a file. */
Open - adds anew entry to fdtable and return the fd number u give to the file,
close - remove that entry from fd table
read - similar to write.
The process_create ,wait are not simple to implement...
Cheers :)