I am trying to build a SDK driver (with no documentation or support from the manufacturer). The original driver uses init_timer() and passes in a pointer to the timer_list structure. And it uses the 'data' element. Now I know that some of the timer functions are deprecated in the newer Linux kernels. Currently I am using kernel version 4.15.
What is the best way to access the 'data' element?
Current function looks like this -
OS_RESULT OS_TimerCreate(OS_DRV_CONTEXT* aContext, OS_TIMER* aTimer, OS_UINT32 aPeriodic, OS_TIMER_FNC aFunction,
OS_VOID* aData, OS_UINT32 aPeriod)
{
struct timer_list* lTimer = (struct timer_list*) aTimer->Space;
unsigned long lJiffies = jiffies;
unsigned long lPeriod = msecs_to_jiffies(aPeriod);
OS_UNREFERENCED_PARAMETER(aContext);
OS_ASSERT( OS_TIMER_SIZE >= sizeof(timer_list));
init_timer(lTimer);
lTimer->expires = lJiffies + lPeriod;
lTimer->data = (unsigned long) aTimer;
aTimer->Function = aFunction;
aTimer->Data = aData;
aTimer->Period = lPeriod;
if (aPeriodic)
{
lTimer->function = OS_TimerPeriodicInternalFunc;
}
else
{
lTimer->function = OS_TimerInternalFunc;
}
add_timer(lTimer);
return OS_RESULT_OK;
}
Declaration for reference -
typedef struct
{
OS_UINT8 Space[OS_TIMER_SIZE];
OS_TIMER_FNC Function;
OS_VOID* Data;
OS_UINT32 Period;
} OS_TIMER;
OS_DECL_EXTERN OS_RESULT OS_TimerCreate(OS_DRV_CONTEXT* aContext, OS_TIMER* aTimer, OS_UINT32 aPeriodic, OS_TIMER_FNC aFunction, OS_VOID* aData, OS_UINT32 aPeriod /* ms */);
Any help will be appreciated.
You first need to change the member that stores the struct timer_list to be of the correct type instead of using an array of bytes:
typedef struct
{
struct timer_list Timer;
OS_TIMER_FNC Function;
OS_VOID* Data;
OS_UINT32 Period;
} OS_TIMER;
(and lTimer is just set to &aTimer->Timer).
In the old code the data member is just set to a pointer to the OS_TIMER structure that contains the timer. In the new code, the callback can instead get this pointer using the from_timer macro, eg if in the old callback you had this:
OS_TIMER *aTimer = lTimer->data;
then in the new code you would instead have:
OS_TIMER *aTimer = from_timer(aTimer, lTimer, Timer);
(where the last parameter Timer is the name of the struct timer_list field in OS_TIMER).
Related
I would like to expose some settings of my device via sysfs. If I understand it right, a driver can have multiple devices, so there should be one instance of the settings variable per device. This should be easy enough using DEVICE_ATTR macro.
Checking the sources I noticed there is also DEVICE_INT_ATTR and other with different type. I wonder what is the intended usage, as they use device_show_int functions that get pointer to device, but don't actually use it:
ssize_t device_store_int(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct dev_ext_attribute *ea = to_ext_attr(attr);
int ret;
long new;
ret = kstrtol(buf, 0, &new);
if (ret)
return ret;
if (new > INT_MAX || new < INT_MIN)
return -EINVAL;
*(int *)(ea->var) = new;
/* Always return full write size even if we didn't consume all */
return size;
}
EXPORT_SYMBOL_GPL(device_store_int);
I searched kernel sources for those macros, and it seems that they work with a global variable. For example DEVICE_INT_ATTR is used in drivers/base/core.c for mca_cfg.tolerant:
static DEVICE_INT_ATTR(tolerant, 0644, mca_cfg.tolerant);
but the mca_cfg varaible is actually global, not tied to a device:
struct mca_config mca_cfg __read_mostly = {
.bootlog = -1,
/* ... */
.tolerant = 1,
.monarch_timeout = -1
};
which makes it look like a driver (not device) attribute.
I also checked commit that adds these macros but it did not help me much.
You correctly take that DEVICE_INT_ATTR and other macros from that family are for "global" attributes, which store and show methods doesn't use dev parameter.
If you want to define attribute, which can be bound to several devices, then you could write your own store and show methods which gets information about the value from dev.
E.g. by having device
struct my_device
{
struct device base;
int repetition;
};
you could expose its repetition field in the attribute using following show method:
// Shows value of 'repetition' field of my_device.
static ssize_t repetition_show(struct device *dev, struct device_attribute *attr, char *buf)
{
// Obtain pointer to the real device structure.
struct my_device* my_dev = container_of(dev, struct my_device, base);
return sprintf(buf, "%d\n", my_dev->repetition);
}
Structure of such attribute could be initialized using __ATTR macro:
static struct device_attribute repetition_attr =
__ATTR(repetition, S_IRUGO, repetition_show, NULL);
Making "generic" attributes
Assume your device struct contains many int fields, which you want to expose via attributes:
struct my_device
{
struct device base;
int repetition;
int counter;
int value;
};
In that case you could generalize attribute definition, so you don't need to create many show (and store) functions.
E.g. you could store offset of the exposed field in your attribute structure:
struct device_bounded_attr
{
struct device_attribute base_attr;
size_t field_offset;
};
// Initializer for struct device_bounded_attr
//
// - real_device_type - type of the actual device structure
// - device_member - member of type 'struct device' in the actual device structure
// - field_member - member in actual device structure which you want to expose as attribute.
#define BOUNDED_ATTR(name, mode, show, store, real_device_type, device_member, field_member) { \
.base_attr = __ATTR(name, mode, show, store), \
.field_offset = offsetof(real_device_type, field_member) - offsetof(real_device_type, device_member)
}
Using this field, you could rewrite show method as follows:
// Shows value of integer field, stored in device.
static ssize_t bounded_attr_show(struct device *dev, struct device_attribute *attr, char *buf)
{
// Obtain pointer to the real attribute structure.
struct device_bounded_attr* bounded_attr = container_of(attr, struct device_bounded_attr, base_attr);
// Having offset of the field, calculate pointer to it
int field_ptr* = (int*)(((char*)dev) + bounded_attr->field_offset);
return sprintf(buf, "%d\n", *field_ptr);
}
So attributes can be declared as follows:
static struct device_bounded_attr repetition_attr =
BOUNDED_ATTR(repetition, S_IRUGO, bounded_attr_show, NULL, struct my_device, base, repetition);
static struct device_bounded_attr counter_attr =
BOUNDED_ATTR(counter, S_IRUGO, bounded_attr_show, NULL, struct my_device, base, counter);
static struct device_bounded_attr value_attr =
BOUNDED_ATTR(counter, S_IRUGO, bounded_attr_show, NULL, struct my_device, base, value);
I am attempting to implement my own version of a semaphore into a linux vm and am running into a crash when I attempt to lock a spinlock inside the down function. Using GDB I found that the down is called immediately after the create function so the problem is definitely there.
Here is the create function:
asmlinkage long sys_create(int value, char name[32], char key[32]){
struct sem *new_sem = (struct sem*) kmalloc(sizeof(struct sem), GFP_ATOMIC);
struct sem_node *new_sem_node = (struct sem_node*) kmalloc(sizeof(struct sem_node), GFP_ATOMIC);
struct sem_node *curr_sem = sem_list_head;
new_sem_node->sem = new_sem;
spin_lock(&sem_lock);
new_sem->sem_id = IDcntr++;
spin_lock_init(&(new_sem->lock));
strncpy(new_sem->key, key, 32);
strncpy(new_sem->name, name, 32);
if(curr_sem == NULL)
{
sem_list_head = new_sem_node;
}
else
{
while(curr_sem->next != NULL)
{
curr_sem = curr_sem->next;
}
curr_sem->next = new_sem_node;
}
spin_unlock(&sem_lock);
return new_sem->sem_id;
}
Functions spin_lock, spin_unlock, and spin_lock_init are working as intended. The down function calls:
spin_lock(&(sem_list_head->sem->lock));
right at the beginning and freezes. To be more specific, in the gdb terminal, I try and get to the next line and it stops and in the actual machine it's completely stopped. No other functions are called between the create and down function. Below is the header file that defines the sem_node, process_node, and sem objects used in the create and down functions:
int IDcntr = 1;
DEFINE_SPINLOCK(sem_lock);
struct sem_node
{
struct sem* sem;
struct sem_node* next;
};
struct process_node
{
struct process_node* next;
struct task_struct* task;
};
struct sem
{
int value;
long sem_id;
spinlock_t lock;
char key[32];
char name[32];
struct process_node* head;
struct process_node* tail;
};
struct sem_node* sem_list_head = NULL;
Through independent testing the function DEFINE_SPINLOCK and object spinlock_t are working as intended. After thorough debugging the problem is in the create function. I freely admit that I am still learning how semaphores work so chances are I didn't set variables correctly or define things correctly. Any help in pointing me the right way would be greatly appreciated.
I was understanding an I2C driver for adxl34x sensor.
If I only keep of_device_id, my probe does not gets called, but if I include i2c_device_id probe gets called.
I checked for some explanation but I get to know that i2c_device_id is used for legacy purpose or board file matching.
Here I am using device tree.
How is it possible that i2c_device_id is making the device recognised?
Is there a dependency in I2C drivers to use both i2c_Device_id and of_device_id??
here is my understanding on this top
id_table is used for legacy i2c devices. See in this code
static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
const struct i2c_client *client)
{
while (id->name[0]) {
if (strcmp(client->name, id->name) == 0)
return id;
id++;
}
return NULL;
}
There is no device id table reference, while of_device_id
/**
* of_match_device - Tell if a struct device matches an of_device_id list
* #ids: array of of device match structures to search in
* #dev: the of device structure to match against
*
* Used by a driver to check whether an platform_device present in the
* system is in its list of supported devices.
*/
const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct device *dev)
{
if ((!matches) || (!dev->of_node))
return NULL;
return of_match_node(matches, dev->of_node);
}
Uses dev->of_node
So its safe to say both mechanism are isolated and does not depend on each other.
Then why my driver is not getting probed by only using this,
/*
static const struct i2c_device_id adxl34x_id[] = {
{ "adxl345", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, adxl34x_id);
*/
#ifdef CONFIG_OF
static const struct of_device_id adxl34x_of_id[] = {
/*
* The ADXL346 is backward-compatible with the ADXL345. Differences are
* handled by runtime detection of the device model, there's thus no
* need for listing the "adi,adxl346" compatible value explicitly.
*/
{ .compatible = "adi,adxl345", },
/*
* Deprecated, DT nodes should use one or more of the device-specific
* compatible values "adi,adxl345" and "adi,adxl346".
*/
{ .compatible = "adi,adxl34x", },
{ }
};
MODULE_DEVICE_TABLE(of, adxl34x_of_id);
#endif
static struct i2c_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
//.pm = &adxl34x_i2c_pm,
.of_match_table = of_match_ptr(adxl34x_of_id),
},
.probe = adxl34x_i2c_probe,
.remove = adxl34x_i2c_remove,
//.id_table = adxl34x_id, /*commented i2c_device_id*/
};
Here are some links that I have gone through in order to get some understanding
https://patches.linaro.org/patch/16873/
https://lists.ozlabs.org/pipermail/linuxppc-dev/2015-July/131965.html
https://i2c.wiki.kernel.org/index.php/OF_Modalias
I understood that first of_* style match will happen, then i2c_device_id type match.
In my case, then how of_* is not able to bind then?
Why i2c_device_table is needed if its legacy thing?
You are right. It is true that you need to pass id_table along with the driver structure for I2C if you are using probe callback.
This is because the earlier I2C driver framework used older style of probe function signature that required i2c_device_id to be passed as the second parameter. However, this has now been replaced with i2c_probe_new callback whose function signature shows that it no more needs i2c_device_id parameter anymore.
Here is a link to this code change for reference:
https://elixir.bootlin.com/linux/v5.16.9/source/include/linux/i2c.h#L281
On kernel 4.0, when stepping through the kernel source for sysfs_create_bin_file, I notice it passes to sysfs_add_file(kobj->sd, &attr->attr, true); The &attr->attr being the struct attribute struct within the bin_attribute struct.
This makes sense until I visit sysfs_add_file_mode_ns, which is directly called from sysfs_add_file, and on line #277 sets temp variable stuct bin_attribute *battr = (void*)attr;
Isn't this pointing to a struct attribute at this point, how is it resolving this to the proper struct (due to the call to sysfs_add_file using &attr->attr on line #483)?
Code
int sysfs_create_bin_file(struct kobject *kobj,
const struct bin_attribute *attr)
{
BUG_ON(!kobj || !kobj->sd || !attr);
return sysfs_add_file(kobj->sd, &attr->attr, true);
}
int sysfs_add_file(struct kernfs_node *parent, const struct attribute *attr,
bool is_bin)
{
return sysfs_add_file_mode_ns(parent, attr, is_bin, attr->mode, NULL);
}
int sysfs_add_file_mode_ns(struct kernfs_node *parent,
const struct attribute *attr, bool is_bin,
umode_t mode, const void *ns)
{
struct lock_class_key *key = NULL;
const struct kernfs_ops *ops;
struct kernfs_node *kn;
loff_t size;
if (!is_bin) {
...
} else {
struct bin_attribute *battr = (void *)attr;
...
}
Line
stuct bin_attribute *battr = (void*)attr;
correctly obtains pointer to the bin_attribute structure from the pointer to its first field attr of type struct attribute.
Normally, Linux kernel developers tend to use container_of macro for obtaining pointer to the structure type knowing pointer to its field. More "canonical" way for the transformation above would be:
stuct bin_attribute *battr = container_of(attr, struct bin_attribute, attr);
(In this call the first attr argument refers to the pointer, and the third attr argument refers to the field's name).
static struct dll_wifi_state **dll_states;
enum dll_type {
DLL_UNSUPPORTED,
DLL_ETHERNET,
DLL_WIFI
};
struct dll_state {
enum dll_type type;
union {
struct dll_eth_state *ethernet;
struct dll_wifi_state *wifi;
} data;
};
static struct dll_state *dll_states = NULL;
struct dll_wifi_state {
int link;
// A pointer to the function that is called to pass data up to the next layer.
up_from_dll_fn_ty nl_callback;
bool is_ds;
};
This is the method whose pointer is being passed in the dll_wifi_state struct.
static void up_from_dll(int link, const char *data, size_t length)
{
//some code here
}
In other file, I am calling this method
void reboot_accesspoint()
{
// We require each node to have a different stream of random numbers.
CNET_srand(nodeinfo.time_of_day.sec + nodeinfo.nodenumber);
// Provide the required event handlers.
CHECK(CNET_set_handler(EV_PHYSICALREADY, physical_ready, 0));
// Prepare to talk via our wireless connection.
CHECK(CNET_set_wlan_model(my_WLAN_model));
// Setup our data link layer instances.
dll_states = calloc(nodeinfo.nlinks + 1, sizeof(struct dll_state));
for (int link = 0; link <= nodeinfo.nlinks; ++link) {
switch (linkinfo[link].linktype) {
case LT_LOOPBACK:
dll_states[link].type = DLL_UNSUPPORTED;
break;
case LT_WAN:
dll_states[link].type = DLL_UNSUPPORTED;
break;
case LT_LAN:
dll_states[link].type = DLL_ETHERNET;
dll_states[link].data.ethernet = dll_eth_new_state(link, up_from_dll);
break;
case LT_WLAN:
dll_states[link].type = DLL_WIFI;
dll_states[link].data.wifi = dll_wifi_new_state(link,
up_from_dll,
true /* is_ds */);
break;
}
}
// printf("reboot_accesspoint() complete.\n");
}
It works fine like this, but I want to add another argument i.e. up_from_dll((int link, const char *data, size_t length, int seq). And as soon as I add this argument, following error starts coming up
ap.c:153: warning: passing argument 2 of ‘dll_wifi_new_state’ from incompatible pointer type
Is there a way of adding another argument to that method without getting error ??? I am really bad with pointers :(
Any help would be much appreciated.
Line 153 :
dll_states[link].data.wifi = dll_wifi_new_state(link,
up_from_dll,
true /* is_ds */);
And method
struct dll_wifi_state *dll_wifi_new_state(int link,
up_from_dll_fn_ty callback,
bool is_ds)
{
// Ensure that the given link exists and is a WLAN link.
if (link > nodeinfo.nlinks || linkinfo[link].linktype != LT_WLAN)
return NULL;
// Allocate memory for the state.
struct dll_wifi_state *state = calloc(1, sizeof(struct dll_wifi_state));
// Check whether or not the allocation was successful.
if (state == NULL)
return NULL;
// Initialize the members of the structure.
state->link = link;
state->nl_callback = callback;
state->is_ds = is_ds;
return state;
}
I haven't changed anything else apart from adding the new parameter to up_from_dll.
The second parameter to dll_wifi_new_state is up_from_dll_fn_ty callback.
It's not in your code listing right now, but up_from_dll_fn_ty is a typedef saying that the up_from_dll_fn_ty is a function pointer with specific parameters (which don't include int seq)
When you updated up_from_dll with different parameters, it no longer matches the type specified by up_from_dll_fn_ty and expected as the second parameter for dll_wifi_new_state. You'll need to add the parameter to up_from_dll_fn_ty and you should be good.
If you post the definition of up_from_dll_fn_ty, it would make the question have all the information and allow me to help you more if you still need it.
You're looking for something like:
typedef void (*up_from_dll_fn_ty)(int link, const char *data, size_t length);
and change it to
typedef void (*up_from_dll_fn_ty)(int link, const char *data, size_t length, int seq);
Here's a link to a question that has good information about creating typedefs for function pointers:
Understanding typedefs for function pointers in C