How do you link a device to a custom sysfs class? - linux

I'm writing drivers for several pieces of custom hardware. All of the devices are attached via PCIe to a host computer. For convenience I would like to group all of these custom devices together into a sysfs class (which I believe is an acceptable thing to do?). Unfortunately the information in LDD3 is way out of date and I'm having trouble finding current documentation that discusses what I'm attempting to do.
Creating my custom class is easy enough:
struct class MY_CLASS = class_create(THIS_MODULE, "myclass")
And inside of my probe calls I've got access to the struct dev:
static int probe(struct pci_dev *pcidev, const struct pci_device_id *id)
{
...
struct dev *my_dev = &pcidev->dev;
...
}
My question is this: now that I've got the class and the dev, how do I create a link between the two?
The device_create() basically does what I want, but since I've already got a struct dev my understanding is that I shouldn't call device_create (i.e. create a new device) again.
I've done a little more tracing and found that device_add() which is called by device_create(), calls device_add_class_symlinks() (not exported unfortunately) which does something like this:
...
sysfs_create_link(&dev->class->p->subsys.kobj,&dev->kobj, dev_name(dev));
...
I tried something like this directly in my drivers to create the links I want but I can't get it to compile because struct subsys_private (the "p" member in the class struct) is not exposed anywhere?
Any help is greatly appreciated!

Are your drivers sitting on the specific bus? If no, what purpose of the specific class?
Anyway, for starter
struct class devclass = {…}
probe()
{
struct device *dev = …
dev->class = &devclass;
}
init()
{
class_register(&devclass);
}

I've encountered the same issue.
if i called device_register with my class pointer assigned to the device class member. it will create a subsystem in my device directory, which is what device_add_class_symlinks do. but in my device directory there is already subsystem directory which is the link to the bus my device is attached to.
don't know if you got a method

Related

Using GPIOs within a kernel module

i am quiet new at writing kernel drivers and there is something bothering me a lot. It would be great if you could kcik me into the right direction.
I am writing a module for a device, that has to be powered via putting a GPIO to HIGH-State.
In Documentation/gpio/* are texts, which say i should use the new descriptor-based interface of the GPIO Framework. But how to use it?
When i make an include like #include
it compiles and i can run the driver. But using gpiod_get(...) just returns fffffffffffffffe. It makes sense somehow, as the implentation of that function within linux/gpio/consumer.h is
static inline struct gpio_desc *__must_check gpiod_get(struct device
*dev, const char *con_id,enum gpiod_flags flags){
return ERR_PTR(-ENOSYS);
}
The implementation of the function exists in drivers/gpio/devres.c as well. How can i use that one?
It looks to me as i am not supposed to use that implementation.
I hope you can help me as it is getting really irritating.
As it turned out it was just necessary to include the file gpio/gpiolib as well which delivers additional definitions.

dev_err() function definition

I can see that dev_*() family of functions such as dev_err() are given as prototype in include/linux/device.h, but no where I could find its definition. I have visited sites like lxr.free-electrons, but without success. Used tags in the source code of linux kernel, even then failed.
What I am trying to find is how the dev_err(const struct device *dev, const char *fmt, ...) is able to get the device information such as pci bus, etc from just giving const struct device *dev as argument to print in logs.
Description of the device is constructed in function create_syslog_header, defined in drivers/base/core.c. The function just extracts some fields from struct device object, and emits them via snprintf() into the string.
The function dev_err is implemented via define_dev_printk_level macro in the same file (drivers/base/core.c).

Using IDispatchImpl with an Unregistered Interface in an MFC+ATL EXE

I started the project as an MFC Application (for the GUI..), and later added support for ATL.
I then coded a simple ATL-COM object implementing a non registered dual interface using IDispatchImpl, with the 0xfff for Major and Minor, to tell ATL to load the TLB from the EXE.
I skip some details, but at the end, after some debugging I found that the CComTypeInfoHolder::GetTI implementation in atlcom.h was NOT trying to load the TLB from the EXE, but was searching it in the registry. Reason : a m_plibid variable was NOT corresponding to the DECLARE_LIBID macro use in my ATL::CAtlMfcModule declaration.
After some googling I found Bug: CAtlMfcModule::InitLibId() not called and added a call to InitLibId in my module CTOR.
Works fine, now.
Question: Is that a known bug? with a known fix? I am not confortable with my workaround of such an old bug. Is there another way of dealing with that?
UPDATE: additional information, as an answer states there is no bug...
IDispatchImpl Class:
By default, the IDispatchImpl class looks up the type information for
T in the registry. To implement an unregistered interface, you can use
the IDispatchImpl class without accessing the registry by using a
predefined version number. If you create an IDispatchImpl object that
has 0xFFFF as the value for wMajor and 0xFFFF as the value for wMinor,
the IDispatchImpl class retrieves the type library from the .dll file
instead of the registry.
Excerpt from CComTypeInfoHolder::GetTI Implementation in atlcom.h:
if (InlineIsEqualGUID( CAtlModule::m_libid, *m_plibid) &&
m_wMajor == 0xFFFF &&
m_wMinor == 0xFFFF ) {
TCHAR szFilePath[MAX_PATH];
DWORD dwFLen = ::GetModuleFileName(_AtlBaseModule.GetModuleInstance(), szFilePath, MAX_PATH);
[...]
hRes = LoadTypeLib(pszFile, &pTypeLib);
} else {
[...]
hRes = LoadRegTypeLib(*m_plibid, m_wMajor, m_wMinor, lcid, &pTypeLib);
So, it seems clear to me that there is an advertised behavior: use 0xffff for minor and major and ATL will try to load the typelib from module, not from registry, provided that your CAtlModule::m_libid is up todate. How is CAtlModule::m_libid expected to be be up to date? By using the DECLARE_LIBID macros. How does work that macro? by defining a static InitLibId function, which set up CAtlModule::m_libid.
The bug: when your module derives from ATL::CAtlMfcModule, the defined InitLibId function is NOT called (as ATL::CAtlMfcModule is not a class template)
You are correct, if you are using -1 for major/minor versions, then is is assumed that type information would be taken from the binary. This however does not work with MFC projects: DECLARE_LIBID only works up to CAtlMfcModule class but not its descendants.
A quick fix might be like this, in atlbase.h:
//class CAtlMfcModule :
// public ATL::CAtlModuleT<CAtlMfcModule>
template <typename T>
class CAtlMfcModuleT :
public ATL::CAtlModuleT<T>
and then in your project:
//class CMFCApplication1Module :
// public ATL::CAtlMfcModule
class CMFCApplication1Module :
public ATL::CAtlMfcModuleT<CMFCApplication1Module>
If you post it on MS Connect as a bug, you can leave a link here for others to go upvote the bug.

Probe in Linux DevFreq Driver Not Being Called

I am trying to set up a devfreq driver for a peripheral on Linux. My init method for the driver looks as follows:
static struct platform_driver zynq_csortfreq_driver = {
.probe = zynq_csortfreq_probe,
.driver = {
.name = "ZYNQ_CSORT_DEVFREQ",
.owner = THIS_MODULE,
},
};
static int __init zynq_csortfreq_init(void)
{
return platform_driver_register(&zynq_csortfreq_driver);
}
late_initcall(zynq_csortfreq_init);
However, the probe function (zynq_csortfreq_probe) in my driver never seems to get called. I've read that in order for the probe call to work correctly, the .name value of the driver must match the name of the device - where can I find the name of the device?
In order for the probe function to be called, you must add a device from a machine file or via the device tree. This is typically done with platform_device_register() or platform_add_devices() in machine files. Alternatively, of_platform_populate() is used for the device tree model, but code does not use this directly. The platform device documentation has information for your Linux kernel version. It seems that your Linux uses the device tree model. The documentation in the cpufree devicetree will have some helpful information on activating your driver for this board with device trees.
The dtsi file needs something like,
soc {
zyncfreq#addr {
compatible="xxxx"
/* Other platform data */
Which will define the device for your machine. I would suggest that first you modify your machine files init_machine entry and use platform_device_register() to associate your driver with a device. Then you can later attempt to get the device tree mechanism working if you wish.
If you can view this closed question, my answer might be helpful if the Linux device-model documentation is not completely clear. However, I think for your case the Linux docs are sufficient.
SOLVED:
Problem is in the makefile system. A "dummy" object file must be created and the two "real" files must be combined into the "dummy" object file.
So, new makefile:
#
# Makefile for the mcp3202 driver.
#
obj-$(CONFIG_MCP3202) := mcp3202.o
mcp3202-objs := mcp3202_core.o mcp3202_pru.o
The original "mcp3202.c" was renamed to "mcp3202_core.c". The listed "mcp3202.o" does not need a corresponding .c file since it is created "out of thin air" by the make system by combining mcp3202_core.o and mcp3202_pru.o.
Not very elegant but explains why there's a lot of "_core.c" files strung through out the KERNEL build system. Sounds like an value-added opportunity for a Kernel guru to work on...

get pointer for existing device class (struct class) in Linux kernel module

get pointer for existing device class (struct class) in Linux kernel module
Hi all!
I am trying to register a device in an existing device class, but I am having trouble getting the pointer to an existing class. Kernel version is Linux 3.3.6.
I can create a class in a module, get the pointer to it and then use it to register the device with:
*cl = class_create(THIS_MODULE, className);
dev_ret = device_create(*cl, NULL, *dev, NULL, driverName);
However I need to register another device in the same class with another module, but I couldn't find a way to get the pointer to an existing class. And I can not create the class again in the other module, because since class already exists class_create returns NULL and not the pointer to the class required by device_create.
I found in:
http://lwn.net/Articles/102500/
A function that returns a pointer to a class by its name:
struct class * class_find(char * name)
However when I try to compile the function compiler says it does not exist.
I thought this function was exported by the kernel (my module have license GPL) but it appears it is not.
Maybe I need to include some header?
I tried to rewrite this function since, its code is list in the above link. But when I try to iterate over class_subsys with:
list_for_each_entry(this_class, &class_subsys.kset.list, subsys.kset.kobj.entry)
now symbol class_subsys is not found. Again I thought it is exported to the kernel.
I am not sure what is missing. Some header?
Am I doing it the wrong way?
There is another function to do it?
I suppose if I could traverse sysfs from start I could get a pointer to an existing class.
But I also did not find how to start traversing sysfs.
All functions I have seen requires a pointer to kobject or kset to start traversing. But I have no pointer even to the root of sysfs or kernel objects, so I can not start traversing the tree to get a class pointer.
Can anyone point me in the right direction please?
I think input core is done this way, here is the snippet
Take a look at: https://github.com/torvalds/linux/blob/master/drivers/input/input.c#L1720
Best regards!

Resources