RTC initialisation in an MCU - why use a global callback - c

The code below is related to the initialization of an RTC in an MCU.
Would anybody know the rational for passing NULL to rtc_init() and then setting a global callback global_rtc_cb equal to it.
Why would you use a global callback at all when there is an other function called rtc_callback defined and used as the callback in the struct.
int main() {
rtc_init(NULL);
}
//-----------------------------------------------------------------
void ( * global_rtc_cb)(void *);
int rtc_init(void (*cb)(void *)) {
rtc_config_t cfg;
cfg.init_val = 0;
cfg.alarm_en = true;
cfg.alarm_val = ALARM;
cfg.callback = rtc_callback;
cfg.callback_data = NULL;
global_rtc_cb = cb;
irq_request(IRQ_RTC_0, rtc_isr_0);
clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK);
rtc_set_config(QM_RTC_0, &cfg);
return 0;
}
//---------------------------------------------------------------------
/**
* RTC configuration type.
*/
typedef struct {
uint32_t init_val; /**< Initial value in RTC clocks. */
bool alarm_en; /**< Alarm enable. */
uint32_t alarm_val; /**< Alarm value in RTC clocks. */
/**
* User callback.
*
* #param[in] data User defined data.
*/
void (*callback)(void *data);
void *callback_data; /**< Callback user data. */
} rtc_config_t;

The rtc_ functions are part of the RTC driver. The RTC driver has something driver-specific to do when the event that prompts the callback occurs. This driver-specific stuff happens in rtc_callback. But there may also be other application-specific stuff that the application must do when the event occurs. The application-specific stuff should be done at the application layer, not within the driver. So if the application has something to do in response to the event it can provide a callback to rtc_init. Surely rtc_callback calls global_rtc_cb so that both the driver-specific stuff and the application-specific stuff is performed when the event occurs. Apparently your particular application doesn't need to do anything for this event so it passes NULL to rtc_init. But a different application that uses the same driver may provide a callback function.

Related

Why do some linux header files define a function to return 0 after the declaration?

I am looking at the Linux 4.14 kernel's include/linux/clk.h file, and have noticed that some of the functions are declared, and then later defined to return 0 or NULL.
For example:
struct clk *clk_get(struct device *dev, const char *id);
...
static inline struct clk *clk_get(struct device *dev, const char *id)
{
return NULL;
}
What is the purpose of doing this? I see multiple C source files that fully define this function and still include linux/clk.h.
Linux kernel comes with lots of configuration parameters. For this particular function, you get the service if CONFIG_HAVE_CLK parameter is defined:
#ifdef CONFIG_HAVE_CLK
/**
* clk_get - lookup and obtain a reference to a clock producer.
* #dev: device for clock "consumer"
* #id: clock consumer ID
*
* Returns a struct clk corresponding to the clock producer, or
* valid IS_ERR() condition containing errno. The implementation
* uses #dev and #id to determine the clock consumer, and thereby
* the clock producer. (IOW, #id may be identical strings, but
* clk_get may return different clock producers depending on #dev.)
*
* Drivers must assume that the clock source is not enabled.
*
* clk_get should not be called from within interrupt context.
*/
struct clk *clk_get(struct device *dev, const char *id);
[...]
#else /* !CONFIG_HAVE_CLK */
static inline struct clk *clk_get(struct device *dev, const char *id)
{
return NULL;
}
[...]
This parameter is defined in arch/Kconfig as:
config HAVE_CLK
bool
help
The <linux/clk.h> calls support software clock gating and
thus are a key power management tool on many systems.

Exposing a /dev/uio* file from GPIO input driver

I have made a custom kernel module to handle rising edge triggered interrupts on a GPIO. I want to make a "uio" file for the same in /dev directory. What must I do? Do I need to declare some structures and fill it out ? It would be good if someone could share relevant examples.
Below is the code snippet for the cutom GPIO driver that triggers interrupts.
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h> // Required for the GPIO functions
#include <linux/interrupt.h> // Required for the IRQ code
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Khilav Soni");
MODULE_DESCRIPTION("A Switch test driver");
static unsigned int gpio_switch = 65; ///< hard coding the button gpio for this example to P9_27 (GPIO65)
static unsigned int irq_number; ///< Used to share the IRQ number within this file
/// Function prototype for the custom IRQ handler function -- see below for the implementation
static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);
/** #brief The LKM initialization function
* The static keyword restricts the visibility of the function to within this C file. The __init
* macro means that for a built-in driver (not a LKM) the function is only used at initialization
* time and that it can be discarded and its memory freed up after that point. In this example this
* function sets up the GPIOs and the IRQ
* #return returns 0 if successful
*/
static int __init ebbgpio_init(void){
int result = 0;
printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST LKM\n");
gpio_request(gpio_switch, "sysfs"); // Set up the gpioButton
gpio_direction_input(gpio_switch); // Set the button GPIO to be an input
gpio_set_debounce(gpio_switch, 100); // Debounce the button with a delay of 200ms
//gpio_export(gpio_switch, false); // Causes gpio115 to appear in /sys/class/gpio
// the bool argument prevents the direction from being changed
// Perform a quick test to see that the button is working as expected on LKM load
printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpio_switch));
// GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us
irq_number = gpio_to_irq(gpio_switch);
printk(KERN_INFO "GPIO_TEST: The button is mapped to IRQ: %d\n", irq_number);
// This next call requests an interrupt line
result = request_irq(irq_number, // The interrupt number requested
(irq_handler_t) ebbgpio_irq_handler, // The pointer to the handler function below
IRQF_TRIGGER_RISING, // Interrupt on rising edge (button press, not release)
"switch-event", // Used in /proc/interrupts to identify the owner
NULL); // The *dev_id for shared interrupt lines, NULL is okay
printk(KERN_INFO "GPIO_TEST: The interrupt request result is: %d\n", result);
return result;
}
/** #brief The LKM cleanup function
* Similar to the initialization function, it is static. The __exit macro notifies that if this
* code is used for a built-in driver (not a LKM) that this function is not required. Used to release the
* GPIOs and display cleanup messages.
*/
static void __exit ebbgpio_exit(void){
free_irq(irq_number, NULL); // Free the IRQ number, no *dev_id required in this case
gpio_unexport(gpio_switch); // Unexport the Button GPIO
gpio_free(gpio_switch); // Free the Button GPIO
}
/** #brief The GPIO IRQ Handler function
* This function is a custom interrupt handler that is attached to the GPIO above. The same interrupt
* handler cannot be invoked concurrently as the interrupt line is masked out until the function is complete.
* This function is static as it should not be invoked directly from outside of this file.
* #param irq the IRQ number that is associated with the GPIO -- useful for logging.
* #param dev_id the *dev_id that is provided -- can be used to identify which device caused the interrupt
* Not used in this example as NULL is passed.
* #param regs h/w specific register values -- only really ever used for debugging.
* return returns IRQ_HANDLED if successful -- should return IRQ_NONE otherwise.
*/
static irq_handler_t ebbgpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs){
static unsigned int numberPresses = 0; ///< For information, store the number of button presses
printk(KERN_INFO "GPIO_TEST: Interrupt! (button state is %d)\n", gpio_get_value(gpio_switch));
printk(KERN_INFO "GPIO_TEST: The button was pressed %d times\n", numberPresses);
numberPresses++; // Global counter, will be outputted when the module is unloaded
return (irq_handler_t) IRQ_HANDLED; // Announce that the IRQ has been handled correctly
}
/// This next calls are mandatory -- they identify the initialization function
/// and the cleanup function (as above).
module_init(ebbgpio_init);
module_exit(ebbgpio_exit);

How to share a hardware abstraction struct without making it global

This is a question about sharing data that is "global", mimicking a piece of addressable memory that any function could access.
I'm writing code for an embedded project, where I've decoupled my physical gpio pins from the application. The application communicates with the "virtual" gpio port, and device drivers then communicate with the actual hardware. The primary motivation for this is the comfort it allows me in switching out what pins are connected to what peripheral when developing, and to include things like button matrices that use fewer physical pins while still handling them as regular gpio device registers.
typedef struct GPIO_PinPortPair
{
GPIO_TypeDef *port; /* STM32 GPIO Port */
uint16_t pin; /* Pin number */
} GPIO_PinPortPair;
typedef struct GPIO_VirtualPort
{
uint16_t reg; /* Virtual device register */
uint16_t edg; /* Flags to signal edge detection */
GPIO_PinPortPair *grp; /* List of physical pins associated with vport */
int num_pins; /* Number of pins in vport */
} GPIO_VirtualPort;
This has worked well in the code I've written so far, but the problem is that I feel like I have to share the addresses to every defined virtual port as a global. A function call would look something like this, mimicking the way it could look if I were to use regular memory mapped io.
file1.c
GPIO_VirtualPort LEDPort;
/* LEDPort init code that associates it with a list of physical pins */
file2.c
extern GPIO_VirtualPort LEDPort;
vgpio_write_pin(&LEDPort, PIN_1, SET_PIN);
I've searched both SO and the internet for best practices when it comes to sharing variables, and I feel like I understand why I should avoid global variables (no way to pinpoint where in code something happens to the data) and that it's better to use local variables with pointers and interface functions (like a "get current tick" function rather than reading a global tick variable).
My question is, given that I want to the keep the syntax as simple as possible, what is the best way to define these struct variables and then make them available for functions in other modules to use? Is it okay to use these struct variables as globals? Should I use some kind of master-array of pointers to every virtual port I have and use a getter function to avoid using extern variables?
I like to do it this way:
file1.h
typedef enum
{
VirtualPortTypeLED
} VirtualPortType;
typedef struct GPIO_PinPortPair
{
GPIO_TypeDef *port; /* STM32 GPIO Port */
uint16_t pin; /* Pin number */
} GPIO_PinPortPair;
typedef struct GPIO_VirtualPort
{
uint16_t reg; /* Virtual device register */
uint16_t edg; /* Flags to signal edge detection */
GPIO_PinPortPair *grp; /* List of physical pins associated with vport */
int num_pins; /* Number of pins in vport */
} GPIO_VirtualPort;
file1.c
GPIO_VirtualPort LEDPort;
void VirtualPortInit()
{
/* fill in all structures and members here */
LEDPort.reg = 0x1234;
...
}
GPIO_VirtualPort *VirtualPortGet(VirtualPortType vpt)
{
switch(vpt) {
case VirtualPortTypeLED:
return &LEDPort;
}
return NULL;
}
file2.c
#include file1.h
GPIO_VirtualPort *myLed;
VirtualPortInit();
myLed = VirtualPortGet(VirtualPortTypeLED);
Btw, I didn't compile this ... :)
To do this without using a global struct that references a given set of hardware or a global set of addresses you create a handle to the GPIO struct at the location that you want when starting out.
I'm not sure how the STM32 is laid out as I have no experience with that family of devices but I have seen and used this method in the situation you describe.
If your hardware is located at a particular address in memory, eg: 0x50, then your calling code asks a GPIO_Init() to give it a handle to the memory at that location. This still allows you to assign the struct at different locations if you need, for example:
/* gpio.h */
#include <stdef.h>
#include <stdint.h>
#include <bool.h>
typedef struct GPIO_Port GPIO_Port; // forward declare the struct definition
GPIO_Port *GPIO_Init(void *memory, const size_t size);
GPIO_Write_Pin(GPIO_Port *port_handle, uint8_t pin number, bool state);
A simple implementation of the GPIO_Init() function might be:
/* gpio.c */
#include "gpio.h"
struct GPIO_Port // the memory mapped struct definition
{
uint16_t first_register;
uint16_t second_register;
// etc, ordered to match memory layout of GPIO registers
};
GPIO_Port *GPIO_Init(void *memory, const size_t size)
{
// if you don't feel the need to check this then the
// second function parameter probably won't be necessary
if (size < sizeof(GPIO_Port *))
return (GPIO_Port *)NULL;
// here you could perform additional operations, e.g.
// clear the memory to all 0, depending on your needs
// return the handle to the memory the caller provided
return (GPIO_Port *)memory;
}
GPIO_Write_Pin(GPIO_Port *port_handle, uint8_t pin number, bool state)
{
uint16_t mask = 1u << pin_number;
if (state == true)
port_handle->pin_register |= mask; // set bit
else
port_handle->pin_register &= ~mask; // clear bit
}
Where the struct itself is defined only within the source file and there is no single global instance. Then you can use this like:
// this can be defined anywhere, or for eg, returned from malloc(),
// as long as it can be passed to the init function
#define GPIO_PORT_START_ADDR (0x50)
// get a handle at whatever address you like
GPIO_Port *myporthandle = GPIO_init(GPIO_PORT_START_ADDR, sizeof(*myporthandle));
// use the handle
GPIO_Write_Pin(myporthandle, PIN_1, SET_HIGH);
For the init function you can pass in the address of the memory with the real hardware location of the GPIO registers, or you can allocate some new block of RAM and pass the address of that.
Your addresses of the used memory do not have to be global, they are just passed to GPIO_Init() from the calling code and so ultimately could come from anywhere, the object handle takes over any subsequent referencing to that chunk of memory by passing to subsequent GPIO function calls. You should be able to build up your more complex functions around this idea of passing in the information that changes and the abstracted mapped memory such that you can still allow the functionality you mention with the "virtual" port.
This method has the benefit of separation of concerns (your GPIO unit is concerned only with the GPIO, not memory, something else can handle that), encapsulation (only the GPIO source needs to concern itself with the members of the GPIO port struct) and no/few globals (the handle can be instantiated and passed around as needed).
Personally I find this pattern pretty handy when it comes to unit testing. In release I pass the address for the real hardware but in test I pass an address for a struct somewhere in memory and test that the members are changed as expected by the GPIO unit - no hardware involved.

RTC on an mcu - function pointers and callbacks

The code below is an example of how to use the real time clock on an mcu.
My question is in relation to callbacks and function pointers.
I have included the struct declaration for rtc_config_t below.
My question is, on the line cfg.callback = rtc_example_callback
Why is the & sign not used before rtc_example_callback.
Why is not necessary to pass the arguments to rtc_example_callback?
The last struct memeber void *callback_data; is set to NULL, I don't understand what this does?
When or what would you want to return?
Many tanks for your inputs
#include "rtc.h"
#include "interrupt.h"
#include "isr.h"
#define ALARM (QM_RTC_ALARM_MINUTE / 6)
#define MAX_RTC_FIRINGS (5)
void rtc_example_callback(void *);
static volatile uint32_t rtc_fired = 0;
/* RTC app example */
int main(void)
{
/* Variables */
rtc_config_t cfg; //create a struct variable to configure the RTC
PRINTF("Starting: RTC\n");
/* Initialise RTC configuration */
cfg.init_val = 0;
cfg.alarm_en = true;
cfg.alarm_val = ALARM;
cfg.callback = rtc_example_callback;
cfg.callback_data = NULL;
irq_request(IRQ_RTC_0, rtc_isr_0); //submit the RTC to the interrupt service routine
clk_periph_enable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK); //switch on RTC and Periphal clock
rtc_set_config(RTC_0, &cfg); //Set the RTC configuration
/* Wait for RTC to fire 5 times and then finish. */
while (rtc_fired < MAX_RTC_FIRINGS) {
}
PRINTF("Finished: RTC\n");
clk_periph_disable(CLK_PERIPH_RTC_REGISTER | CLK_PERIPH_CLK); //turn off the clocks
return 0;
}
void rtc_example_callback(void *data)
{
PUTS("Alarm!!\n");
qm_rtc_set_alarm(RTC_0, (RTC[RTC_0].rtc_ccvr + ALARM));
rtc_fired++;
}
-----------------------------------------------------------------------
/**
* RTC configuration type.
*/
typedef struct {
uint32_t init_val; /**< Initial value in RTC clocks. */
bool alarm_en; /**< Alarm enable. */
uint32_t alarm_val; /**< Alarm value in RTC clocks. */
/**
* User callback.
*
* #param[in] data User defined data.
*/
void (*callback)(void *data);
void *callback_data; /**< Callback user data. */
} rtc_config_t;
name of the function is a pointer to the function
function will be called with arguments from rtc library, you are not invoking it (you cannot pass arguments here).
I guess that NULL assigned to custom_callback will not call custom method from library (default function or no function will be called), just assign NULL if you dont want to use custom callback.
usually library code looks like:
if(custom_callback)
{
custom_callback(some_parameters);
}
else
{
default_callback(some_parameters);
}

How to offload NAPI poll function to workqueue

I'm working with linux 3.3, Ethernet driver for smsc911x. and I want to move the NAPI poll function to workqueue.
My questions are :
1. How do I pass the NAPI poll function arguments to the work_struct?
2. How do I get the NAPI poll function arguments back from the work_struct? (related to Q.1 above)
3. How can I return the npackets value to the original NAPI poll function caller?
Here are some explanations :
Current NAPI poll function reads recevie FIFO directly which I want to change to do it with DMA controller. For this DMA, I trigger DMA, sleep with wait_event_interruptible, and get woken up by DMA's ISR with wake_up_interruptible. As you know, NAPI poll function is in interrupt context (softirq) so I cannot sleep there for DMA completion. I want to move the NAPI poll function(reading RX FIFO) to waitqueue(process context) usnig a work_struct.
The problem is, NAPI poll function is called by the kernel with two arguments : struct napi_struct *napi and int budget.
I want to pass those argument to the work_struct and queue the work_struct to the workqueue (using queue_work function).
the work_struct looks like below. (include/linux/workqueue.h)
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
I take that atomic_long_t data is for passing the argument to the work_struct. how can I pass the arguments to the work_struct?
I tried this (I added in the structure for device driver struct smsc911x_data a member struct work_struct rx_work for passing the work.) :
struct work_arg { // a new struct for pass the arguments
struct napi_struct *napi;
int budget;
};
/* NAPI poll function */
static int smsc911x_poll(struct napi_struct *napi, int budget) {
struct smsc911x_data *pdata =
container_of(napi, struct smsc911x_data, napi);
struct net_device *dev = pdata->dev;
int npackets = 0;
if (enable_rx_use_dma == 1) { // when using DMA for FIFO read
prom_printf("moving it to workqueue\n");
struct work_arg *p;
p = kzalloc(sizeof(struct work_arg), GFP_KERNEL);
p->napi = napi;
p->budget = budget;
pdata->rx_work.data = (atomic_long_t) p; // <== THIS LINE
prom_printf("queue work, with napi = %x, budget = %d\n", napi, budget);
queue_work(rx_work_workqueue, &pdata->rx_work); // smsc911x_poll_work } else {
-- original NAP poll function, reads FIFO until it's empty and enables the RX interrupt and
-- keeps the number of processed packets to npackets.
return npackets;
}
For "THIS LINE" above, I'm getting error during compile.
with pdata->rx_work.data = p; , I get error: incompatible types when assigning to type 'atomic_long_t' from type 'struct work_arg *'
with pdata->rx_work.data = (atomic_long_t) p; , I get error: conversion to non-scalar type requested.
Also, in the new work function, How can I extract the original argments? I tried this below which gives me errors.
/* New work function called by the default worker thread */ static int smsc911x_poll_work(struct work_struct *work) {
struct smsc911x_data *pdata =
container_of(work, struct smsc911x_data, rx_work);
struct net_device *dev = pdata->dev;
int npackets = 0;
struct napi_struct *napi = (struct work_struct *)work->data.napi; // <== THIS LINE
int budget = (struct work_struct *)work->data.budget; // <== THIS LINE ..
}
From the above 'THIS LINE's, I get erros below.
error: 'atomic_long_t' has no member named 'napi'
error: 'atomic_long_t' has no member named 'budget'
and I don't know how to pass the return value to the original NAPI poll functino caller.
I'm not sure if this kind of conversion (from NAPI poll to workqueue) is possible.
Sorry for the long questions but any help will be greatly appreciated.
ADD : Because struct smsc911x_data has both struct napi napi; and struct work_struct rx_work; as members, I can easily obtain the struct napi *napi from work_struct *work (an argument of work function) by :
struct smsc911x_data *pdata =
container_of(work, struct smsc911x_data, rx_work); struct napi_struct *napi = &pdata.napi;
so maybe I can just pass the int budget through a new member value in struct smsc911x_data. I sill want to know the correct practice for this case.
How do I pass the NAPI poll function arguments to the work_struct?
Just create new structure, which embed work_struct and add your arguments into it:
struct my_work {
struct work_struct base_work;// Embedded work_struct
struct napi_struct *napi; // Your arguments
int budget;
};
static int smsc911x_poll(struct napi_struct *napi, int budget) {
struct my_work* p = kmalloc(sizeof(*p), GFP_ATOMIC /* Flag usable for interrupt context */);
INIT_WORK(&p->base_work, smsc911x_poll_work); // Initialize underliying structure.
p->budget = budget; // Initialize your members
p->napi = napi;
...
}
How do I get the NAPI poll function arguments back from the work_struct? (related to Q.1 above)
Use container_of:
static int smsc911x_poll_work(struct work_struct *work) {
struct my_work* p = container_of(work, struct my_work, base_work);
...
}
How can I return the npackets value to the original NAPI poll function caller?
As I understand from description(see, e.g., http://www.linuxfoundation.org/collaborate/workgroups/networking/napi) this function should process packets which are ready. And this processing should be done within function itself, without deferring to workqueue or similar.
This approach seems very ineffective since you need two interrupts, one when packet is received, and one when DMA tansfer is done.
I think this it the way of working of DMA capable network interfaces:
When packet(s) arrive, Socket Buffers are already allocated and mapped to DMA memory buffer, and DMA is armed.
Packet is transferred from NIC to Socket Buffer through DMA
NIC raises hardware interrupt (when DMA transfer is done).
Hardware interrupt handler schedules packet receiving software interrupt (SOFTIRQ)
SOFTIRQ does NAPI poll() for further processing.
NAPI poll() process packets in DMA buffers and and passes it to upper layers as sk_buff and initializes new DMA buffers. if all packets (quota) are processed, IRQ is enabled and NAPI is told to stop polling.

Resources