Commit 194b9e3c authored by H Hartley Sweeten's avatar H Hartley Sweeten Committed by Greg Kroah-Hartman

staging: comedi: icp_multi: use attach_pci callback

Convert this PCI driver to use the comedi PCI auto config attach
mechanism by adding an 'attach_pci' callback function. Since the
driver does not require any external configuration options, and
the legacy 'attach' callback is now optional, remove it. The
boardinfo is also not needed now so remove it also.

This also allows removing the icp_multi.h header completely.
Signed-off-by: default avatarH Hartley Sweeten <hsweeten@visionengravers.com>
Cc: Ian Abbott <abbotti@mev.co.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 798cdd05
......@@ -44,10 +44,7 @@ There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V
4 x 16-bit counters
Options:
[0] - PCI bus number - if bus number and slot number are 0,
then driver search for first unused card
[1] - PCI slot number
Configuration options: not applicable, uses PCI auto config
*/
#include <linux/interrupt.h>
......@@ -56,8 +53,6 @@ There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V
#include <linux/delay.h>
#include <linux/pci.h>
#include "icp_multi.h"
#define PCI_DEVICE_ID_ICP_MULTI 0x8000
#define ICP_MULTI_ADC_CSR 0 /* R/W: ADC command/status register */
......@@ -117,18 +112,10 @@ static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 };
Data & Structure declarations
==============================================================================
*/
static unsigned short pci_list_builded; /*>0 list of card is known */
struct boardtype {
const char *name; /* driver name */
int device_id;
};
struct icp_multi_private {
struct pcilst_struct *card; /* pointer to card */
char valid; /* card is usable */
void __iomem *io_addr; /* Pointer to mapped io address */
resource_size_t phys_iobase; /* Physical io address */
unsigned int AdcCmdStatus; /* ADC Command/Status register */
unsigned int DacCmdStatus; /* DAC Command/Status register */
unsigned int IntEnable; /* Interrupt Enable register */
......@@ -144,7 +131,6 @@ struct icp_multi_private {
};
#define devpriv ((struct icp_multi_private *)dev->private)
#define this_board ((const struct boardtype *)dev->board_ptr)
/*
==============================================================================
......@@ -696,60 +682,43 @@ static int icp_multi_reset(struct comedi_device *dev)
return 0;
}
static int icp_multi_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
static int icp_multi_attach_pci(struct comedi_device *dev,
struct pci_dev *pcidev)
{
struct comedi_subdevice *s;
resource_size_t iobase;
int ret;
unsigned int irq;
struct pcilst_struct *card = NULL;
resource_size_t io_addr[5], iobase;
unsigned char pci_bus, pci_slot, pci_func;
comedi_set_hw_dev(dev, &pcidev->dev);
dev->board_name = dev->driver->driver_name;
ret = alloc_private(dev, sizeof(struct icp_multi_private));
if (ret < 0)
return ret;
/* Initialise list of PCI cards in system, if not already done so */
if (pci_list_builded++ == 0)
pci_card_list_init(PCI_VENDOR_ID_ICP, 0);
card = select_and_alloc_pci_card(PCI_VENDOR_ID_ICP,
this_board->device_id, it->options[0],
it->options[1]);
if (card == NULL)
return -EIO;
devpriv->card = card;
if ((pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0],
&irq)) < 0)
return -EIO;
ret = comedi_pci_enable(pcidev, dev->board_name);
if (ret)
return ret;
iobase = pci_resource_start(pcidev, 2);
dev->iobase = iobase;
iobase = io_addr[2];
devpriv->phys_iobase = iobase;
devpriv->io_addr = ioremap(iobase, ICP_MULTI_SIZE);
if (devpriv->io_addr == NULL)
if (!devpriv->io_addr)
return -ENOMEM;
dev->board_name = this_board->name;
ret = comedi_alloc_subdevices(dev, 5);
if (ret)
return ret;
icp_multi_reset(dev);
if (irq) {
if (request_irq(irq, interrupt_service_icp_multi,
IRQF_SHARED, "Inova Icp Multi", dev)) {
irq = 0; /* Can't use IRQ */
}
if (pcidev->irq) {
ret = request_irq(pcidev->irq, interrupt_service_icp_multi,
IRQF_SHARED, dev->board_name, dev);
if (ret == 0)
dev->irq = pcidev->irq;
}
dev->irq = irq;
s = &dev->subdevices[0];
dev->read_subdev = s;
s->type = COMEDI_SUBD_AI;
......@@ -811,6 +780,8 @@ static int icp_multi_attach(struct comedi_device *dev,
static void icp_multi_detach(struct comedi_device *dev)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
if (dev->private)
if (devpriv->valid)
icp_multi_reset(dev);
......@@ -818,27 +789,17 @@ static void icp_multi_detach(struct comedi_device *dev)
free_irq(dev->irq, dev);
if (dev->private && devpriv->io_addr)
iounmap(devpriv->io_addr);
if (dev->private && devpriv->card)
pci_card_free(devpriv->card);
if (--pci_list_builded == 0)
pci_card_list_cleanup(PCI_VENDOR_ID_ICP);
if (pcidev) {
if (dev->iobase)
comedi_pci_disable(pcidev);
}
}
static const struct boardtype boardtypes[] = {
{
.name = "icp_multi",
.device_id = PCI_DEVICE_ID_ICP_MULTI,
},
};
static struct comedi_driver icp_multi_driver = {
.driver_name = "icp_multi",
.module = THIS_MODULE,
.attach = icp_multi_attach,
.attach_pci = icp_multi_attach_pci,
.detach = icp_multi_detach,
.num_names = ARRAY_SIZE(boardtypes),
.board_name = &boardtypes[0].name,
.offset = sizeof(struct boardtype),
};
static int __devinit icp_multi_pci_probe(struct pci_dev *dev,
......
/*
comedi/drivers/icp_multi.h
Stuff for ICP Multi
Author: Anne Smorthit <anne.smorthit@sfwte.ch>
*/
#ifndef _ICP_MULTI_H_
#define _ICP_MULTI_H_
#include "../comedidev.h"
/****************************************************************************/
struct pcilst_struct {
struct pcilst_struct *next;
int used;
struct pci_dev *pcidev;
unsigned short vendor;
unsigned short device;
unsigned char pci_bus;
unsigned char pci_slot;
unsigned char pci_func;
resource_size_t io_addr[5];
unsigned int irq;
};
struct pcilst_struct *inova_devices;
/* ptr to root list of all Inova devices */
/****************************************************************************/
static void pci_card_list_init(unsigned short pci_vendor, char display);
static void pci_card_list_cleanup(unsigned short pci_vendor);
static struct pcilst_struct *find_free_pci_card_by_device(unsigned short
vendor_id,
unsigned short
device_id);
static int find_free_pci_card_by_position(unsigned short vendor_id,
unsigned short device_id,
unsigned short pci_bus,
unsigned short pci_slot,
struct pcilst_struct **card);
static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id,
unsigned short device_id,
unsigned short pci_bus,
unsigned short pci_slot);
static int pci_card_alloc(struct pcilst_struct *amcc);
static int pci_card_free(struct pcilst_struct *amcc);
static void pci_card_list_display(void);
static int pci_card_data(struct pcilst_struct *amcc,
unsigned char *pci_bus, unsigned char *pci_slot,
unsigned char *pci_func, resource_size_t * io_addr,
unsigned int *irq);
/****************************************************************************/
/* build list of Inova cards in this system */
static void pci_card_list_init(unsigned short pci_vendor, char display)
{
struct pci_dev *pcidev = NULL;
struct pcilst_struct *inova, *last;
int i;
inova_devices = NULL;
last = NULL;
for_each_pci_dev(pcidev) {
if (pcidev->vendor == pci_vendor) {
inova = kzalloc(sizeof(*inova), GFP_KERNEL);
if (!inova) {
printk
("icp_multi: pci_card_list_init: allocation failed\n");
pci_dev_put(pcidev);
break;
}
inova->pcidev = pci_dev_get(pcidev);
if (last) {
last->next = inova;
} else {
inova_devices = inova;
}
last = inova;
inova->vendor = pcidev->vendor;
inova->device = pcidev->device;
inova->pci_bus = pcidev->bus->number;
inova->pci_slot = PCI_SLOT(pcidev->devfn);
inova->pci_func = PCI_FUNC(pcidev->devfn);
/* Note: resources may be invalid if PCI device
* not enabled, but they are corrected in
* pci_card_alloc. */
for (i = 0; i < 5; i++)
inova->io_addr[i] =
pci_resource_start(pcidev, i);
inova->irq = pcidev->irq;
}
}
if (display)
pci_card_list_display();
}
/****************************************************************************/
/* free up list of amcc cards in this system */
static void pci_card_list_cleanup(unsigned short pci_vendor)
{
struct pcilst_struct *inova, *next;
for (inova = inova_devices; inova; inova = next) {
next = inova->next;
pci_dev_put(inova->pcidev);
kfree(inova);
}
inova_devices = NULL;
}
/****************************************************************************/
/* find first unused card with this device_id */
static struct pcilst_struct *find_free_pci_card_by_device(unsigned short
vendor_id,
unsigned short
device_id)
{
struct pcilst_struct *inova, *next;
for (inova = inova_devices; inova; inova = next) {
next = inova->next;
if ((!inova->used) && (inova->device == device_id)
&& (inova->vendor == vendor_id))
return inova;
}
return NULL;
}
/****************************************************************************/
/* find card on requested position */
static int find_free_pci_card_by_position(unsigned short vendor_id,
unsigned short device_id,
unsigned short pci_bus,
unsigned short pci_slot,
struct pcilst_struct **card)
{
struct pcilst_struct *inova, *next;
*card = NULL;
for (inova = inova_devices; inova; inova = next) {
next = inova->next;
if ((inova->vendor == vendor_id) && (inova->device == device_id)
&& (inova->pci_bus == pci_bus)
&& (inova->pci_slot == pci_slot)) {
if (!(inova->used)) {
*card = inova;
return 0; /* ok, card is found */
} else {
return 2; /* card exist but is used */
}
}
}
return 1; /* no card found */
}
/****************************************************************************/
/* mark card as used */
static int pci_card_alloc(struct pcilst_struct *inova)
{
int i;
if (!inova) {
printk(" - BUG!! inova is NULL!\n");
return -1;
}
if (inova->used)
return 1;
if (comedi_pci_enable(inova->pcidev, "icp_multi")) {
printk(" - Can't enable PCI device and request regions!\n");
return -1;
}
/* Resources will be accurate now. */
for (i = 0; i < 5; i++)
inova->io_addr[i] = pci_resource_start(inova->pcidev, i);
inova->irq = inova->pcidev->irq;
inova->used = 1;
return 0;
}
/****************************************************************************/
/* mark card as free */
static int pci_card_free(struct pcilst_struct *inova)
{
if (!inova)
return -1;
if (!inova->used)
return 1;
inova->used = 0;
comedi_pci_disable(inova->pcidev);
return 0;
}
/****************************************************************************/
/* display list of found cards */
static void pci_card_list_display(void)
{
struct pcilst_struct *inova, *next;
printk("Anne's List of pci cards\n");
printk("bus:slot:func vendor device io_inova io_daq irq used\n");
for (inova = inova_devices; inova; inova = next) {
next = inova->next;
printk
("%2d %2d %2d 0x%4x 0x%4x 0x%8llx 0x%8llx %2u %2d\n",
inova->pci_bus, inova->pci_slot, inova->pci_func,
inova->vendor, inova->device,
(unsigned long long)inova->io_addr[0],
(unsigned long long)inova->io_addr[2], inova->irq,
inova->used);
}
}
/****************************************************************************/
/* return all card information for driver */
static int pci_card_data(struct pcilst_struct *inova,
unsigned char *pci_bus, unsigned char *pci_slot,
unsigned char *pci_func, resource_size_t * io_addr,
unsigned int *irq)
{
int i;
if (!inova)
return -1;
*pci_bus = inova->pci_bus;
*pci_slot = inova->pci_slot;
*pci_func = inova->pci_func;
for (i = 0; i < 5; i++)
io_addr[i] = inova->io_addr[i];
*irq = inova->irq;
return 0;
}
/****************************************************************************/
/* select and alloc card */
static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id,
unsigned short device_id,
unsigned short pci_bus,
unsigned short pci_slot)
{
struct pcilst_struct *card;
int err;
if ((pci_bus < 1) & (pci_slot < 1)) { /* use autodetection */
card = find_free_pci_card_by_device(vendor_id, device_id);
if (card == NULL) {
printk(" - Unused card not found in system!\n");
return NULL;
}
} else {
switch (find_free_pci_card_by_position(vendor_id, device_id,
pci_bus, pci_slot,
&card)) {
case 1:
printk
(" - Card not found on requested position b:s %d:%d!\n",
pci_bus, pci_slot);
return NULL;
case 2:
printk
(" - Card on requested position is used b:s %d:%d!\n",
pci_bus, pci_slot);
return NULL;
}
}
err = pci_card_alloc(card);
if (err != 0) {
if (err > 0)
printk(" - Can't allocate card!\n");
/* else: error already printed. */
return NULL;
}
return card;
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment