Linux I2C device driver probe function is not called - linux

I am trying to connect Analog Devices` ADV7182 video encoder chip which has I2C communication to config the chip and control MIPI video data over CSI-2.
The issue is that the probe function of the driver is not called unless I create a new I2C device manually in __init function. Like this:
static struct i2c_board_info i2c_board_info_adv[] = {
{
I2C_BOARD_INFO("adv7281-m", 0x21)
}};
static int __init adv7180_initialize (void) {
struct i2c_client *client;
struct i2c_adapter *adapter;
int i2c_bus_number = 3;
int ret = i2c_register_board_info(i2c_bus_number, i2c_board_info_adv, ARRAY_SIZE(i2c_board_info_adv));
if (ret) {
printk("ADV7180 i2c_register_board_info failed. Result %d\n", ret);
return -EINVAL;
}
ret = i2c_add_driver(&adv7180_driver);
if (ret) {
printk("ADV7180 i2c_add_driver failed. Result %d\n", ret);
return -EINVAL;
}
adapter = i2c_get_adapter(i2c_bus_number);
if (!adapter) {
printk("ADV7180 i2c_get_adapter failed. Result %d\n", ret);
return -EINVAL;
}
client = i2c_new_device(adapter, &i2c_board_info_adv[0]);
if (!client) {
printk("ADV7180 i2c_new_device failed. Result %d\n", ret);
return -EINVAL;
}
return 0; }
In the original driver for ADV7xxx devices there is only call of i2c_add_driver in init function. https://github.com/analogdevicesinc/linux/tree/adv7280 Unfortunately, I cannot use that driver directly because of different kernels versions (since it uses backward incompatible versions of video for linux) and kernel upgrade does not seem to work either for the device I use (NanoPC).
I am quite new to linux drivers so I think I do not understand something about the platform. Any help?

Related

Could I/O memory access be used inside ISR under Linux (ARM)?

I'm creating driver for communication with FPGA under Linux. FPGA is connected via GPMC interface. When I tested read/write from driver context - everithing works perfectly. But the problem is that I need to read some address on interrupt. So I created interrupt handler, registred it and put iomemory reading in it (readw function). But when interrupt is fired - only zero's are readed. I tested every part of driver from the top to the bottom and it seems like the problem is in iomemory access inside ISR. When I replaced io access with constant value - it successfully passed to user-level application.
ARM version: armv7a (Cortex ARM-A8 (DM3730))
Compiler: CodeSourcery 2014.05
Here is some code from driver which represents performed actions:
// Request physical memory region for FPGA address IO
void* uni_PhysMem_request(const unsigned long addr, const unsigned long size) {
// Handle to be returned
void* handle = NULL;
// Check if memory region successfully requested (mapped to module)
if (!request_mem_region(addr, size, moduleName)) {
printk(KERN_ERR "\t\t\t\t%s() failed to request_mem_region(0x%p, %lu)\n", __func__, (void*)addr, size);
}
// Remap physical memory
if (!(handle = ioremap(addr, size))) {
printk(KERN_ERR "\t\t\t\t%s() failed to ioremap(0x%p, %lu)\n", __func__, (void*)addr, size);
}
// Return virtual address;
return handle;
}
// ...
// ISR
static irqreturn_t uni_IRQ_handler(int irq, void *dev_id) {
size_t readed = 0;
if (irq == irqNumber) {
printk(KERN_DEBUG "\t\t\t\tIRQ handling...\n");
printk(KERN_DEBUG "\t\t\t\tGPIO %d pin is %s\n", irqGPIOPin, ((gpio_get_value(irqGPIOPin) == 0) ? "LOW" : "HIGH"));
// gUniAddr is a struct which holds GPMC remapped virtual address (from uni_PhysMem_request), offset and read size
if ((readed = uni_ReadBuffer_IRQ(gUniAddr.gpmc.addr, gUniAddr.gpmc.offset, gUniAddr.size)) < 0) {
printk(KERN_ERR "\t\t\t\tunable to read data\n");
}
else {
printk(KERN_INFO "\t\t\t\tdata readed success (%zu bytes)\n", readed);
}
}
return IRQ_HANDLED;
}
// ...
// Read buffer by IRQ
ssize_t uni_ReadBuffer_IRQ(void* physAddr, unsigned long physOffset, size_t buffSize) {
size_t size = 0;
size_t i;
for (i = 0; i < buffSize; i += 2) {
size += uni_RB_write(readw(physAddr + physOffset)); // Here readed value sent to ring buffer. When "readw" replaced with any constant - everything OK
}
return size;
}
Looks like the problem was in code optimizations. I changed uni_RB_write function to pass physical address and data size, also read now performed via ioread16_rep function. So now everything works just fine.

How to dereference device_private in struct device

I'm working on a driver in Linux. I'm working on getting some /sys file attributes in place that will make things nicer. In delivering what these attributes are to tell, the attribute functions must have access to some data that's stored by the driver. Because of how things appear to be made and stored, I thought I could use the device_private *p member of the struct device that comes from device_create(). Basically, it's like this:
for (i = 0; i < total; i++) {
pDevice = device_create(ahcip_class, NULL, /*no parent*/
MKDEV(AHCIP_MAJOR, AHCIP_MINOR + i), NULL, /*no additional info*/
DRIVER_NAME "%d", AHCIP_MINOR + i);
if (IS_ERR(pDevice)) {
ret = PTR_ERR(pDevice);
printk(KERN_ERR "%s:%d device_create failed AHCIP_MINOR %d\n",
__func__, __LINE__, (AHCIP_MINOR + i));
break;
}
mydevs[i].psysfs_dev = pDevice;
ret = sysfs_create_group(&pDevice->kobj, &attr_group);
if (!ret) {
pr_err("%s:%d failed in making the device attributes\n",
__func__, __LINE__);
goto build_udev_quick_out;
}
}
This doesn't yet show the assignment into the device_private pointer, but that's where I'm headed. Each new device made under this class will need the same attributes thus the group. Here's my single attribute that I'm starting with for "proof of concept"
static ahcip_dev *get_ahcip_dev(struct kobject *ko)
{
ahcip_dev *adev = NULL;
struct device *pdev = container_of(ko, struct device, kobj);
if (!pdev) {
pr_err("%s:%d unable to find device struct in kobject\n",
__func__, __LINE__);
return NULL;
}
/* **** problem dereferencing p **** */
adev = (ahcip_dev*)pdev->p->driver_data;
/* return the pointer anyway, but if it's null, print to klog */
if (!adev)
pr_err("%s:%d no ahcip_dev, private driver data is NULL\n",
__func__, __LINE__);
/* **** again problem dereferencing p **** */
return pdev->p->(ahcip_dev*)driver_data; // <--- problem here
}
static ssize_t pxis_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buff)
{
u32 pi = 0;
ahcip_dev *adev = get_ahcip_dev(kobj);
/* get_ahcip_dev() will print what happened, this needs to return
* error code
*/
if (!adev)
return -EIO;
pi = adev->port_index;
return sprintf(buff, "%08x\n", get_port_reg(adev->hba->ports[pi], 0x10));
}
I figured that, since device_create() returns a struct device* and I'm using that to make the device group, the struct kobject* that is coming into pxis_show is the member of the device structure made by device_create. If this is true, then I should be able to stuff some private data into that object and use it when the /sys files are accessed. However, when the lines of code marked above dereference the p member I get dereferencing pointer of incomplete type from gcc. I've determined that it's the struct device_private member of struct device that is incomplete but why? Is there a different structure I should be using? This seems to be something truly internally by the kernel.
For assign private data for device, you need to use void *drvdata parameter to device_create(). After creation, data can be accessed via dev_get_drvdata(pdev).
struct device_private is internal for device implementation. From description of this structure (drivers/base/base.h):
Nothing outside of the driver core should ever touch these fields.

IOCTL Method - Linux

I have an exam question and I can't quite see how to solve it.
A driver that needs the ioctl method to be implemented and tested.
I have to write the ioctl() method, the associated test program as well as the common IOCTL definitions.
The ioctl() method should only handle one command. In this command, I need to transmit a data structure from user space to kernel space.
Below is the structure shown:
struct data
{
     char label [10];
     int value;
}
The driver must print the IOCTL command data, using printk();
Device name is "/dev/mydevice"
The test program must validate driver mode using an initialized data structure.
Hope there are some that can help
thanks in advance
My suggestion:
static int f_on_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret;
switch (cmd)
{
case PASS_STRUCT:
struct data pass_data;
ret = copy_from_user(&pass_data, arg, sizeof(*pass_data));
if(ret < 0)
{
printk("PASS_STRUCT\n");
return -1;
}
printk(KERN ALERT "Message PASS_STRUCT : %d and %c\n",pass_data.value, pass_data.label);
break;
default:
return ENOTTY;
}
return 0;
}
Definitions:
Common.h
#define SYSLED_IOC_MAGIC 'k'
#define PASS_STRUCT _IOW(SYSLED_IOC_MAGIC, 1, struct data)
The test program:
int main()
{
int fd = open("/dev/mydevice", O_RDWR);
data data_pass;
data_pass.value = 2;
data_pass.label = "hej";
ioctl(fd, PASS_STRUCT, &data_pass);
close(fd);
return 0;
}
Is this completely wrong??

Call to ioctl() on a usb device using usbfs does not work

I am trying to create my own driver for my Gamepad right now, I found out the original reason why I wanted to create it does not exist but I still want to do it for the experience. So please don't tell me there is a better way to do this than writing my own driver.
The part in kernelspace with the ioctl function that should be called is:
static int xpad_ioctl (struct usb_interface *intf, unsigned int code,void *buf) {
//struct usb_xpad *xpad = usb_get_intfdata(intf);
printk(KERN_INFO"(Ongy)IOCTL called\n");
//if (_IOC_TYPE(code) != XPAD_IOMAGIC) return -ENOTTY;
//if (_IOC_NR(code) > XPAD_IOMAX) return -ENOTTY;
switch(code){
case XPAD_IORMAP:
printk(KERN_INFO"(Ongy)IORMAP called\n");
break;
default:
return -EINVAL;
}
return 0;
}
static struct usb_driver xpad_driver =
{
.name = "Cyborg-V5-driver",
.probe = xpad_probe,
.disconnect = xpad_disconnect,
.unlocked_ioctl = xpad_ioctl,
.id_table = xpad_table,
};
The part in userspace to call it is (this is part of a Qt-application):
int openfile() {
char *device = "/dev/bus/usb/005/009";
printf("Opening device %s\n", device);
return open(device, /*O_RDONLY*/O_WRONLY | O_NONBLOCK );
}
[...] the closefile(int file_desc) is missing here, this and the openfile functions exist because of me not knowing one can call "::open()" when Qt overrides function calls.
void MainContainer::callioctl() {
int file_desc, ret_val;
errno = 0;
file_desc = openfile();
if (file_desc==-1){
printf("Ioctl notcalled because of: error %s\n", strerror(errno));
}
else
{
errno = 0;
//struct usbdevfs_getdriver* driver = (usbdevfs_getdriver*)malloc(sizeof(struct usbdevfs_getdriver));
struct mappingpair* pair = (mappingpair*)malloc(sizeof(struct mappingpair));
ret_val = ioctl(file_desc, XPAD_IORMAP, pair);
//printf("Drivername %s\n", driver->driver);
closefile(file_desc);
if (ret_val==-1) printf("Ioctl failed with error %s\n", strerror(errno));
else printf("Ioctl call successfull\n");
}
}
ok, the string to the file I open I get with a call to lsusb and change it by hand in the code, this is only for debugging and until I get the ioctl calls working
When I call the callioctl() it prints:
Ioctl failed with error Unpassender IOCTL (I/O-Control) für das Gerät
The German part means "wrong ioctl (I/O-Control) for the device" and nothing appears in dmesg, that is why I think my ioctl function in the driver is not called.
If you look at http://www.hep.by/gnu/kernel/usb/usbfs.html it says that to send an ioctl to the usb_driver device you need to do:
struct usbdevfs_ioctl {
int ifno;
int ioctl_code;
void *data;
};
/* user mode call looks like this.
* 'request' becomes the driver->ioctl() 'code' parameter.
* the size of 'param' is encoded in 'request', and that data
* is copied to or from the driver->ioctl() 'buf' parameter.
*/
static int
usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
{
struct usbdevfs_ioctl wrapper;
wrapper.ifno = ifno;
wrapper.ioctl_code = request;
wrapper.data = param;
return ioctl (fd, USBDEVFS_IOCTL, &wrapper);
}
The documentation is listing usb device under /proc/bus so admittedly this may have changed.

ARM char device driver initialization isn't creating /dev/ file

I am writing a driver for the GPIO pins on an ARM platform.
My driver works correctly and I've avoided the problem until
now by manually mknod'ing a device file.
my initialization code:
static int __init gpio_init (void)
{
void *ptr_error;
if (register_chrdev(249, "gpio_device", &fops) < 0){
printk(KERN_INFO "Registering device failed\n");
return -EINVAL;
}
if ((device_class = class_create(THIS_MODULE, "gpio_device"))
== NULL){
unregister_chrdev_region(DEV_T, 1);
printk(KERN_INFO "Class creation failed\n");
return -EINVAL;
}
ptr_error = device_create(device_class, NULL, DEV_T, NULL, "gpio_device");
if (IS_ERR(ptr_error)){
class_destroy(device_class);
unregister_chrdev_region(DEV_T, 1);
printk(KERN_INFO "Device creation failed\n");
return -EINVAL;
}
cdev_init(&c_dev, &fops);
if (cdev_add(&c_dev, DEV_T, 1)){
device_destroy(device_class, DEV_T);
class_destroy(device_class);
unregister_chrdev_region(DEV_T, 1);
printk(KERN_INFO "Cdev add failed\n");
return -EINVAL;
}
printk(KERN_INFO "Guten tag, GPIO driver initialized\n");
return SUCCESS;
}
This runs with no errors, except no file "gpio_device" is created in /dev.
I'm cross compiling for ARM onto kernel 2.6.39.4. (using arm-linux-gcc)
As I understand it, device_create should be creating the /dev file.
I tried running your code and found a few mistakes:
When you register with register_chrdev(), you should unregister with unregister_chrdev(). unregister_chrdev_region() is used to unregister a registration done with alloc_chrdev_region() or register_chrdev_region().
A call to register_chrdev() registers minor numbers 0-255 for the given major, and sets up a default cdev structure for each, therefore, you do not need to deal with the cdev_init() & cdev_add().
You should check the error using IS_ERR & PTR_ERR for class_create() & device_create() as PTR_ERR will turn the return pointer to the error code with a cast.
You can read more here: Char Device Registration.
After applying the modification I mentioned, the /dev/gpio_device is created without mknod:
int init_module(void)
{
void *ptr_error;
struct cdev* c_dev;
int result=0;
/* register_chrdev */
result=register_chrdev(my_major, "gpio_device", &fops);
if (result < 0)
{
printk(KERN_INFO "Registering device failed\n");
return result;
}
DEV_T = MKDEV(my_major, my_minor);
/* class_create */
device_class = class_create(THIS_MODULE, "gpio_device");
if (IS_ERR(device_class))
{
unregister_chrdev(my_major, "gpio_device");
printk(KERN_INFO "Class creation failed\n");
return PTR_ERR(device_class);
}
/* device_create */
ptr_error = device_create(device_class, NULL, DEV_T, NULL, "gpio_device");
if (IS_ERR(ptr_error))
{
class_destroy(device_class);
unregister_chrdev(my_major, "gpio_device");
printk(KERN_INFO "Device creation failed\n");
return PTR_ERR(ptr_error);
}
/* //removed
cdev_init(&c_dev, &fops);
if (cdev_add(&c_dev, DEV_T, 1)){
device_destroy(device_class, DEV_T);
class_destroy(device_class);
unregister_chrdev_region(DEV_T, 1);
printk(KERN_INFO "Cdev add failed\n");
return -EINVAL;
}*/
printk(KERN_INFO "Guten tag, GPIO driver initialized\n");
return SUCCESS;
}
I just figured out what was going on here.
We are using BuildRoot to create our custom
linux, and the it turns out we had compiled
out the udev device file management system.
So that's why this doesn't work.

Resources