List all devices bound to a driver - linux-kernel

Let's say I have drivers A and B in the Linux kernel space, with devices bound to them. I would like to export API in the driver A to B to provide list of devices bound to the driver A. Is it possible for a driver A to get to know about all devices currently being detected and bound to that driver?

Yes, simply register functions with A when driver B loads and call same function whenever device list is required.
e.g
Driver A <<< register_func(func_ptr_list); export register_func
Driver B <<< Call register_func with function list.
Multiple driver talks to each other using similar function element. for example Look at module_int for cxgb4 and cxgb4i

If your driver is pci driver, then:
void get_all_devices_of_driver(const char *driver_name)
{
bool found = false;
struct pci_dev *pdev = NULL;
for_each_pci_dev (pdev) {
if (!strcmp(dev_driver_string(&pdev->dev),
driver_name)) {
// do what you want
}
}
}
Or use kernel's general helper function:
/**
* driver_for_each_device - Iterator for devices bound to a driver.
* #drv: Driver we're iterating.
* #start: Device to begin with
* #data: Data to pass to the callback.
* #fn: Function to call for each device.
*
* Iterate over the #drv's list of devices calling #fn for each one.
*/
int driver_for_each_device(struct device_driver *drv, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!drv)
return -EINVAL;
klist_iter_init_node(&drv->p->klist_devices, &i,
start ? &start->p->knode_driver : NULL);
while (!error && (dev = next_device(&i)))
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}

Related

Linux device driver for a Smart Card IC module

I have a smart card IC module, and I want to create a Linux device driver for it. This module is using SPI as the controlling line and has an interrupt line to indicate whether a card is ready. I know how to create a SPI device in Linux kernel and how to read data in the kernel when the interruption happens. But I have no idea on how to transfer the data to the user space (maybe need to create a device node for it), and how to give the user space a interruption to notify it. Does anyone have some suggestion?
One way you can go about this is by creating a devfs entry and then having the interested process open that device and receive asynchronous notification from the device driver using fasync.
Once you have the notification in user space you can notify other interested processes by any means you deem fit.
I am writing a small trimmed down example illustrating this feature.
On the driver side
/* Appropriate headers */
static int myfasync(int fd, struct file *fp, int on);
static struct fasync_struct *fasyncQueue;
static struct file_operations fops =
{
.open = charDriverOpen,
.release = charDriverClose,
.read = charDriverRead,
.write = charDriverWrite,
.unlocked_ioctl = charDriverCtrl,
// This will be called when the FASYNC flag is set
.fasync = myfasync,
};
static int __init charDriverEntry()
{
// Appropriate init for the driver
// Nothing specific needs to be done here with respect to
// fasync feature.
}
static int myfasync(int fd, struct file *fp, int on)
{
// Register the process pointed to by fp to the list
// of processes to be notified when any event occurs
return fasync_helper(fd, fp, 1, &fasyncQueue);
}
// Now to the part where we want to notify the processes listed
// in fasyncQueue when something happens. Here in this example I had
// implemented the timer. Not getting in to the details of timer func
// here
static void send_signal_timerfn(unsigned long data)
{
...
printk(KERN_INFO "timer expired \n");
kill_fasync(&fasyncQueue, SIGIO, POLL_OUT);
...
}
On the user land process side
void my_notifier(int signo, siginfo_t *sigInfo, void *data)
{
printf("Signal received from the driver expected %d got %d \n",SIGIO,signo);
}
int main()
{
struct sigaction signalInfo;
int flagInfo;
signalInfo.sa_sigaction = my_notifier;
signalInfo.sa_flags = SA_SIGINFO;
sigemptyset(&signalInfo.sa_mask);
sigaction(SIGIO, &signalInfo, NULL);
int fp,i;
fp = open("/dev/myCharDevice",O_RDWR);
if (fp<0)
printf("Failed to open\n");
/*New we will own the device so that we can get the signal from the device*/
// Own the process
fcntl(fp, F_SETOWN, getpid());
flagInfo = fcntl(fp, F_GETFL);
// Set the FASYNC flag this triggers the fasync fops
fcntl(fp, F_SETFL, flagInfo|FASYNC);
...
}
Hope this clears things up.
For more detailed reading I suggest you read this

writing an acpi driver in Linux

I need to write a kernel module that uses an acpi method to communicate to a hardware device.
At this point I just want to load the driver and enumerate the devices on the bus.
I found a fairly old but reasonable example on line, below is the basic outline. I pretty much took the example verbatim just changing names, I used acpidump to find the dsdt table get the correct device ID etc.
The driver loads fine, but my add functions are not being called. My suspicion is that I am missing a step to stimulate scanning the bus after I register it. The example assumes the driver is loaded on boot. Is there a way to request the bus be scanned after registering it such that any devices attached to a registered bus will be added? Understand that my suspicion may be wrong so if my assumptions are wrong please correct me.
below is the source:
static int viking_acpi_add(struct acpi_device *device);
static int viking_acpi_remove(struct acpi_device *device);
static void viking_acpi_notify(struct acpi_device *adev, u32 event);
static const struct acpi_device_id nv_device_ids[] = {
{ "ACPI0012", 0},
{ "", 0},
};
MODULE_DEVICE_TABLE(acpi, nv_device_ids);
static struct acpi_driver nv_acpi_driver = {
.name = "NV NVDR",
.class = "NV",
.ids = nv_device_ids,
.ops = {
.add = nv_acpi_add,
.remove = nv_acpi_remove,
.notify = nv_acpi_notify,
},
.owner = THIS_MODULE,
};
//static struct acpi_device acpi_dev;
static int nv_acpi_add(struct acpi_device *device)
{
printk("NV: acpi bus add\n");
return 0;
}
static int nv_remove(struct acpi_device *device)
{
printk("NV: acpi bus remove\n");
return 0;
}
static void nv_acpi_notify(struct acpi_device *adev, u32 event)
{
device_lock(&adev->dev);
printk("notification detected\n");
device_unlock(&adev->dev);
}
static int __init nv_init(void)
{
int result = 0;
result = acpi_bus_register_driver(&nvt_driver);
if (result < 0) {
printk("Error registering driver\n");
return -ENODEV;
}
return 0;
}
static void __exit nv_exit(void)
{
acpi_bus_unregister_driver(&nv_driver);
}
module_init(nv_init);
module_exit(nv_exit);
Well it turns out that another acpi bus driver was registered for the acpi device ID I was using and the kernel did not call my add routine as a consequence. When I ran it with a different kernel, my add routine was called as expected.

Track the connection count of a boost signal

What I'm trying to archive is to get an update if the number of connections to a boost::signal2::signal object is changeing.
To give you the whole picture: I'm writing a GUI application which displays data from a remote server. Each "window" in the application should get it's data for a specific dataset. If a dataset is to be displayed it needs to be remotely subscribed from the server. Multiple windows can display the same dataset (with different ordering or filtering). My goal is to subscribe to a specific dataset only ONCE and disconnect ones its not longer needed.
Background: HFT software, displaying marketdata (orderbooks, trades, ...)
My code so far: I got stuck once I tried to implement the "operator()".
enum UpdateCountMethod {
UP = 1,
DOWN = -1
};
/**
* \brief Connection class which holds a Slot as long as an instance of this class "survives".
*/
class Connection {
public:
Connection(const boost::function<void (int)> updateFunc, const boost::signals2::connection conn) : update(updateFunc), connection(conn) {
update(UP); //Increase counter only. Connection was already made.
}
~Connection() {
update(DOWN); //Decrease counter before disconnecting the slot.
connection.disconnect();
}
private:
const boost::function<void(int)> update; // Functor for updating the connection count.
const boost::signals2::connection connection; // Actual boost connection this object belongs to.
};
/**
* \brief This is a Signal/Slot "container" which number of connections can be tracked.
*/
template<typename Signature>
class ObservableSignal{
typedef typename boost::signals2::slot<Signature> slot_type;
public:
ObservableSignal() : count(0) {}
boost::shared_ptr<Connection> connect(const slot_type &t) {
// Create the boost signal connection and return our shared Connection object.
boost::signals2::connection conn = signal.connect(t);
return boost::shared_ptr<Connection>(new Connection(boost::bind(&ObservableSignal::updateCount, this, _1), conn));
}
// This is where I don't know anymore.
void operator() (/* Parameter depend on "Signature" */) {
signal(/* Parameter depend on "Signature" */); //Call the actual boost signal
}
private:
void updateCount(int updown) {
// TODO: Handle subscription if count is leaving or approaching 0.
count += updown;
std::cout << "Count: " << count << std::endl;
}
int count; // current count of connections to this signal
boost::signals2::signal<Signature> signal; // Actual boost signal
};

How to make the read operation occur only one time in the pSeudo driver here?

I am trying to write a kernel driver program. However, when I do the cat operation on cat /dev/pSeudoDrv. It just keeps printing the value. It never exits. I was assuming that the cat operation should exit after reading once. However, it is reading forever. What is the problem here?
#include <linux/init.h>
#include <linux/module.h> /** needed by all modules **/
#include <linux/kernel.h> /** This is for KERN_ALERT **/
#include <linux/fs.h> /** for file operations **/
#include <linux/cdev.h> /** character device **/
#include <linux/device.h> /** for sys device registration in /dev/ and /sys/class **/
/** for copy_to_user **/
#include <asm/uaccess.h>
/** For class registration to work, you need GPL license **/
MODULE_LICENSE("GPL");
static struct cdev basicCdev;
static struct class *basicDriverClass;
static int basicMajorNumber = 0;
/** Prototype for read, this will be invoked when the read function is done on to the driver **/
/** The declaration type is file operations based function pointer - read **/
static ssize_t basicRead(struct file *filp, char *buffer, size_t length,loff_t *offset);
static int basicOspen(struct inode *inode, struct file *file);
/** File Operations function pointer table **/
/** There are plenty of file operations **/
static struct file_operations fops = {
.read = basicRead,
.write = NULL,
.open = basicOspen,
.release = NULL
};
static ssize_t basicRead(struct file *filp, char *buffer, size_t length, loff_t *offset)
{
char msg[1024] = "Hello SJ_read\0";
printk(KERN_ALERT "The Read operation called\r\n");
copy_to_user( buffer, msg, sizeof(msg) );
return sizeof(msg);
}
static int basicOspen(struct inode *inode, struct file *file)
{
printk("Kernel.Basic Driver Opened now!!\r\n");
return 0;
}
static void setup_cdev(struct cdev *dev, int minor, struct file_operations *fops)
{
int err = -1;
/** MKDEV call creates a device number i.e. combination of major and minor number **/
int devno = MKDEV(basicMajorNumber, minor);
/** Initiliaze character dev with fops **/
cdev_init(dev, fops);
/**owner and operations initialized **/
dev->owner = THIS_MODULE;
dev->ops = fops;
/** add the character device to the system**/
/** Here 1 means only 1 minor number, you can give 2 for 2 minor device, the last param is the count of minor number enrolled **/
err = cdev_add (dev, devno, 1);
if (err)
{
printk (KERN_NOTICE "Couldn't add cdev");
}
}
static int chrDriverInit(void)
{
int result;
dev_t dev;
printk("Welcome!! Device Init now..");
/** int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name); **/
/** dev -> The dev_t variable type,which will get the major number that the kernel allocates. **/
/**The same name will appear in /proc/devices. **/
/** it is registering the character device **/
/** a major number will be dynamically allocated here **/
result = alloc_chrdev_region(&dev, 0, 1, "pSeudoDrv");
if( result < 0 )
{
printk("Error in allocating device");
return -1;
}
/** From these two if's we are avoiding the manual mknod command to create the /dev/<driver> **/
/** creating class, and then device created removes the dependency of calling mknod **/
/** A good method - the mknod way is depreciated **/
/** mknod way is - mknod /dev/<driver_name> c <majorNumber> <minorNumber>
/** add the driver to /sys/class/chardrv **/
if ((basicDriverClass = class_create(THIS_MODULE, "chardrv")) == NULL) //$ls /sys/class
{
unregister_chrdev_region(dev, 1);
return -1;
}
/** add the driver to /dev/pSeudoDrv -- here **/
if (device_create(basicDriverClass, NULL, dev, NULL, "pSeudoDrv") == NULL) //$ls /dev/
{
class_destroy(basicDriverClass);
unregister_chrdev_region(dev, 1);
return -1;
}
/** let's see what major number was assigned by the Kernel **/
basicMajorNumber = MAJOR(dev);
printk("Kernel assigned major number is %d ..\r\n",basicMajorNumber );
/** Now setup the cdev **/
setup_cdev(&basicCdev, 0, &fops);
return 0;
}
static void chrDriverExit(void)
{
/** A reverse - destroy mechansim -- the way it was created **/
printk("Releasing Simple Devs -- %s\r\n", __FUNCTION__);
/** delete the character driver added **/
cdev_del(&basicCdev);
/** destroy the device created **/
device_destroy(basicDriverClass, MKDEV(basicMajorNumber, 0));
/** destroy the class created **/
class_destroy(basicDriverClass);
/** unregister the chr dev **/
unregister_chrdev(basicMajorNumber, "pSeudoDrv");
}
module_init(chrDriverInit);
module_exit(chrDriverExit);
You MUST return 0 to let user-space process know that driver has copied all data and is at end of file.
If you return length, provided in the argument of read file operation, the calls will keep coming.
To avoid this you must increase "loff_t *offset" with the amount of bytes you copied in user-space "char *buffer" and return the exact number. This "*offset" will keep its value when the next read call will arrive.
Now you will get another call for read. You will have to compare your "*offset" with the "size of kernel data" you need to copy to user-space. If "*offset" is greater than or equal to "size of kernel data", you should return 0. This will let user-space program to know that there are no more data available in file (or device) and the process will stop reading.
Look at your return value in basicRead.
From LDD3:
The return value for read is interpreted by the calling application
program:
If the value equals the count argument passed to the read system call, the requested number of bytes has been transferred. This is the
optimal case.
If the value is positive, but smaller than count, only part of the data has been transferred. This may happen for a number of reasons,
depending on the device. Most often, the application program retries
the read. For instance, if you read using the fread function, the
library function reissues the system call until completion of the
requested data transfer.
If the value is 0, end-of-file was reached (and no data was read).
A negative value means there was an error. The value specifies what the error was, according to . Typical values returned
on error include -EINTR (interrupted system call) or -EFAULT (bad
address).
In your case sizeof(msg) is smaller then length and it indicates userspace about partial read.
If you don't care about partial reads you can simply do return length; so userspace would know that read is done.
Otherwise, you should make sense of filp and offset.

libusb is not enumerating devices

Using libusb 1.2.6 I am trying to enumerate all devices on Windows 7 x64.
MinGW is my IDE and project is linked to gcc/libusb.a. Not sure if this one will do the job on x64.
This is the code, taken from examples:
usb_init(); /* initialize the library */
usb_find_busses(); /* find all busses */
usb_find_devices(); /* find all connected devices */
struct usb_bus *busses = usb_get_busses();
for (bus = busses; bus; bus = bus->next) {
struct usb_device *dev;
for (dev = bus->devices; dev; dev = dev->next) {
/* Check if this device is a printer */
if (dev->descriptor.bDeviceClass == 7) {
/* Open the device, claim the interface and do your processing */
}
/* Loop through all of the configurations */
for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
/* Loop through all of the interfaces */
for (i = 0; i < dev->config[c].bNumInterfaces; i++) {
/* Loop through all of the alternate settings */
for (a = 0; a < dev->config[c].interface[i].num_altsetting; a++) {
/* Check if this interface is a printer */
if (dev->config[c].interface[i].altsetting[a].bInterfaceClass == 7) {
/* Open the device, set the alternate setting, claim the interface and do your processing */
}
}
}
}
}
}
It can find 1 bus, but then no devices. I was expecting to see all connected devices.
Eventually what I want is to establish bulk transfer on specific device which already has a driver.

Resources