Problem with PCI Driver on Ubuntu 10.10 i386

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I am trying to develop a very basic PCI device driver for a dummy
device I have created in qemu. The device has no functionality except
that it sits on the PCI bus behind two bridges (bridge 0 on root bus,
bridge 1 only device behind bridge 0, and device behind bridge 1 as
the only device). It is a single function do nothing device with one
MMIO BAR of 0x10000 size. The BAR is initialized by the kernel at some
MMIO location but the device is not disabled, as there is no driver. I
have used one of the available vendor ids for my work.

My driver is not loaded automatically, so I load the driver manually
after the boot of the VM, and then issues a rescan of the entire PCI
bus using "echo 1 > /sys/bus/pci/rescan", but nothing happens. The
probe function of my driver is never invoked, neither does the device
gets visible in lspci output.

Can someone help me identify what I might be doing wrong?

I have attached the driver code, the lspci output, the lspci -H1
output, the lspci -H1 -xxx -s 02:02.0 output that details the
registers of the device.

-- 
Adhyas
********************************************************************
Two types have compatible type if their types are the same.
    — ANSI C Standard, 3.1.2.6.
********************************************************************

Attachment: lspci
Description: Binary data

Attachment: lspci_detailed
Description: Binary data

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  You need a userspace library to cooperate with this driver. It (and other
 *  info) may be obtained here:
 *  http://www.fi.muni.cz/~xslaby/phantom.html
 *  or alternatively, you might use OpenHaptics provided by Sensable.
 */

#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/pci.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/phantom.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>

#include <asm/atomic.h>
#include <asm/io.h>

#define DUMMY_VENDOR_ID             0xFFF0
#define DUMMY_DEVICE_ID             0x8748
#define DUMMY_CLASS_ID              0x0880 // ??

#define DUMMY_MAX_MINORS    1
#define DUMMY_VERSION       1

//static struct class *dummy_class;

struct dummy_device {
	unsigned int opened;
	void __iomem *caddr;
	u32 __iomem *iaddr;
	u32 __iomem *oaddr;
	unsigned long status;
	atomic_t counter;
    wait_queue_head_t wait;

	struct mutex open_lock;
	spinlock_t regs_lock;
};


static irqreturn_t dummy_isr(int irq, void *data)
{
	struct dummy_device *dev = data;

printk("Dummy: %s called\n", __func__);
	atomic_inc(&dev->counter);
	wake_up_interruptible(&dev->wait);

	return IRQ_HANDLED;
}

static int __devinit dummy_probe(struct pci_dev *pdev,
	const struct pci_device_id *pci_id)
{
	struct dummy_device *pht;
	int retval;

printk("Dummy: %s called\n", __func__);
	retval = pci_enable_device(pdev);
	if (retval)
		goto err;

	retval = pci_request_regions(pdev, "dummy");
	if (retval)
		goto err_dis;

	retval = -ENOMEM;
	pht = kzalloc(sizeof(*pht), GFP_KERNEL);
	if (pht == NULL) {
		dev_err(&pdev->dev, "unable to allocate device\n");
        printk("Dummy: unable to allocate device\n");
		goto err_reg;
	}

	pht->caddr = pci_iomap(pdev, 0, 0);
	if (pht->caddr == NULL) {
		dev_err(&pdev->dev, "can't remap conf space\n");
		printk("Dummy: can't remap conf space\n");
		goto err_fr;
	}
	pht->iaddr = pci_iomap(pdev, 2, 0);
	if (pht->iaddr == NULL) {
		dev_err(&pdev->dev, "can't remap input space\n");
		printk("Dummy: can't remap input space\n");
		goto err_unmc;
	}
	pht->oaddr = pci_iomap(pdev, 3, 0);
	if (pht->oaddr == NULL) {
		dev_err(&pdev->dev, "can't remap output space\n");
		printk("Dummy: can't remap output space\n");
		goto err_unmi;
	}

	mutex_init(&pht->open_lock);
	spin_lock_init(&pht->regs_lock);
	init_waitqueue_head(&pht->wait);

	retval = request_irq(pdev->irq, dummy_isr,
			IRQF_SHARED | IRQF_DISABLED, "dummy", pht);
	if (retval) {
		dev_err(&pdev->dev, "can't establish ISR\n");
		printk("Dummy: can't establish ISR\n");
		goto err_unmo;
	}

	pci_set_drvdata(pdev, pht);

	return 0;
err_unmo:
	pci_iounmap(pdev, pht->oaddr);
err_unmi:
	pci_iounmap(pdev, pht->iaddr);
err_unmc:
	pci_iounmap(pdev, pht->caddr);
err_fr:
	kfree(pht);
err_reg:
	pci_release_regions(pdev);
err_dis:
	pci_disable_device(pdev);
err:
	return retval;
}

static void __devexit dummy_remove(struct pci_dev *pdev)
{
	struct dummy_device *pht = pci_get_drvdata(pdev);

printk("Dummy: %s called\n", __func__);
	free_irq(pdev->irq, pht);

	pci_iounmap(pdev, pht->oaddr);
	pci_iounmap(pdev, pht->iaddr);
	pci_iounmap(pdev, pht->caddr);

	kfree(pht);

	pci_release_regions(pdev);

	pci_disable_device(pdev);
}

static int dummy_suspend(struct pci_dev *pdev, pm_message_t state)
{
printk("Dummy: %s called\n", __func__);
	synchronize_irq(pdev->irq);

	return 0;
}

static int dummy_resume(struct pci_dev *pdev)
{
printk("Dummy: %s called\n", __func__);
	return 0;
}


static struct pci_device_id dummy_pci_tbl[] __devinitdata = {
	{ .vendor = DUMMY_VENDOR_ID, .device = DUMMY_DEVICE_ID,
	  .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
	  .class = (DUMMY_CLASS_ID << 8), .class_mask = 0xffff00 },
	{ 0, }
};
MODULE_DEVICE_TABLE(pci, dummy_pci_tbl);

static struct pci_driver dummy_pci_driver = {
	.name = "dummy",
	.id_table = dummy_pci_tbl,
	.probe = dummy_probe,
	.remove = __devexit_p(dummy_remove),
	.suspend = dummy_suspend,
	.resume = dummy_resume,
};

static int __init dummy_init(void)
{
	int retval;

printk("Dummy: %s called\n", __func__);
/*
	dummy_class = class_create(THIS_MODULE, "dummy");
	if (IS_ERR(dummy_class)) {
		retval = PTR_ERR(dummy_class);
		printk("Dummy: can't register dummy class\n");
		goto err;
	}
*/

	retval = pci_register_driver(&dummy_pci_driver);
	if (retval) {
		printk("Dummy: can't register pci driver\n");
		goto err_class;
	}

	printk("Dummy Linux Driver, init OK\n");

	return 0;
err_class:
//	class_destroy(dummy_class);
//err:
	return retval;
}

static void __exit dummy_exit(void)
{
printk("Dummy: %s called\n", __func__);
	pci_unregister_driver(&dummy_pci_driver);

//	class_destroy(dummy_class);

	printk("Dummy: module successfully removed\n");
}

module_init(dummy_init);
module_exit(dummy_exit);
_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@xxxxxxxxxxxxxxxxx
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux