Merge tag 'asoc-v3.10-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / adv_pci_dio.c
index 338c43e716bae1fc7d504b7e86ee598974e9e11d..f70c67471c13a42aa850db35a9352edf70e69202 100644 (file)
@@ -236,8 +236,6 @@ struct diosubd_data {
 
 struct dio_boardtype {
        const char *name;       /*  board name */
-       int vendor_id;          /*  vendor/device PCI ID */
-       int device_id;
        int main_pci_region;    /*  main I/O PCI region */
        enum hw_cards_id cardtype;
        int nsubdevs;
@@ -250,10 +248,8 @@ struct dio_boardtype {
 };
 
 static const struct dio_boardtype boardtypes[] = {
-       {
+       [TYPE_PCI1730] = {
                .name           = "pci1730",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1730,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1730,
                .nsubdevs       = 5,
@@ -263,30 +259,27 @@ static const struct dio_boardtype boardtypes[] = {
                .sdo[1]         = { 16, PCI1730_IDO, 2, 0, },
                .boardid        = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1733] = {
                .name           = "pci1733",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1733,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1733,
                .nsubdevs       = 2,
                .sdi[1]         = { 32, PCI1733_IDI, 4, 0, },
                .boardid        = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1734] = {
                .name           = "pci1734",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1734,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1734,
                .nsubdevs       = 2,
                .sdo[1]         = { 32, PCI1734_IDO, 4, 0, },
                .boardid        = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, },
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1735] = {
                .name           = "pci1735",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1735,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1735,
                .nsubdevs       = 4,
@@ -295,10 +288,9 @@ static const struct dio_boardtype boardtypes[] = {
                .boardid        = { 4, PCI1735_BOARDID, 1, SDF_INTERNAL, },
                .s8254[0]       = { 3, PCI1735_C8254, 1, 0, },
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1736] = {
                .name           = "pci1736",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1736,
                .main_pci_region = PCI1736_MAINREG,
                .cardtype       = TYPE_PCI1736,
                .nsubdevs       = 3,
@@ -306,39 +298,35 @@ static const struct dio_boardtype boardtypes[] = {
                .sdo[1]         = { 16, PCI1736_IDO, 2, 0, },
                .boardid        = { 4, PCI1736_BOARDID, 1, SDF_INTERNAL, },
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1739] = {
                .name           = "pci1739",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1739,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1739,
                .nsubdevs       = 2,
                .sdio[0]        = { 48, PCI1739_DIO, 2, 0, },
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1750] = {
                .name           = "pci1750",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1750,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1750,
                .nsubdevs       = 2,
                .sdi[1]         = { 16, PCI1750_IDI, 2, 0, },
                .sdo[1]         = { 16, PCI1750_IDO, 2, 0, },
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1751] = {
                .name           = "pci1751",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1751,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1751,
                .nsubdevs       = 3,
                .sdio[0]        = { 48, PCI1751_DIO, 2, 0, },
                .s8254[0]       = { 3, PCI1751_CNT, 1, 0, },
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1752] = {
                .name           = "pci1752",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1752,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1752,
                .nsubdevs       = 3,
@@ -346,29 +334,26 @@ static const struct dio_boardtype boardtypes[] = {
                .sdo[1]         = { 32, PCI1752_IDO2, 2, 0, },
                .boardid        = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
                .io_access      = IO_16b,
-       }, {
+       },
+       [TYPE_PCI1753] = {
                .name           = "pci1753",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1753,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1753,
                .nsubdevs       = 4,
                .sdio[0]        = { 96, PCI1753_DIO, 4, 0, },
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1753E] = {
                .name           = "pci1753e",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1753,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1753E,
                .nsubdevs       = 8,
                .sdio[0]        = { 96, PCI1753_DIO, 4, 0, },
                .sdio[1]        = { 96, PCI1753E_DIO, 4, 0, },
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1754] = {
                .name           = "pci1754",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1754,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1754,
                .nsubdevs       = 3,
@@ -376,10 +361,9 @@ static const struct dio_boardtype boardtypes[] = {
                .sdi[1]         = { 32, PCI1754_IDI2, 2, 0, },
                .boardid        = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
                .io_access      = IO_16b,
-       }, {
+       },
+       [TYPE_PCI1756] = {
                .name           = "pci1756",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1756,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1756,
                .nsubdevs       = 3,
@@ -387,19 +371,17 @@ static const struct dio_boardtype boardtypes[] = {
                .sdo[1]         = { 32, PCI1756_IDO, 2, 0, },
                .boardid        = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, },
                .io_access      = IO_16b,
-       }, {
+       },
+       [TYPE_PCI1760] = {
                /* This card has its own 'attach' */
                .name           = "pci1760",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1760,
                .main_pci_region = 0,
                .cardtype       = TYPE_PCI1760,
                .nsubdevs       = 4,
                .io_access      = IO_8b,
-       }, {
+       },
+       [TYPE_PCI1762] = {
                .name           = "pci1762",
-               .vendor_id      = PCI_VENDOR_ID_ADVANTECH,
-               .device_id      = 0x1762,
                .main_pci_region = PCIDIO_MAINREG,
                .cardtype       = TYPE_PCI1762,
                .nsubdevs       = 3,
@@ -1076,31 +1058,50 @@ static int pci_dio_add_8254(struct comedi_device *dev,
        return 0;
 }
 
-static const void *pci_dio_find_boardinfo(struct comedi_device *dev,
-                                         struct pci_dev *pcidev)
+static unsigned long pci_dio_override_cardtype(struct pci_dev *pcidev,
+                                              unsigned long cardtype)
 {
-       const struct dio_boardtype *this_board;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
-               this_board = &boardtypes[i];
-               if (this_board->vendor_id == pcidev->vendor &&
-                   this_board->device_id == pcidev->device)
-                       return this_board;
+       /*
+        * Change cardtype from TYPE_PCI1753 to TYPE_PCI1753E if expansion
+        * board available.  Need to enable PCI device and request the main
+        * registers PCI BAR temporarily to perform the test.
+        */
+       if (cardtype != TYPE_PCI1753)
+               return cardtype;
+       if (pci_enable_device(pcidev) < 0)
+               return cardtype;
+       if (pci_request_region(pcidev, PCIDIO_MAINREG, "adv_pci_dio") == 0) {
+               /*
+                * This test is based on Advantech's "advdaq" driver source
+                * (which declares its module licence as "GPL" although the
+                * driver source does not include a "COPYING" file).
+                */
+               unsigned long reg =
+                       pci_resource_start(pcidev, PCIDIO_MAINREG) + 53;
+
+               outb(0x05, reg);
+               if ((inb(reg) & 0x07) == 0x02) {
+                       outb(0x02, reg);
+                       if ((inb(reg) & 0x07) == 0x05)
+                               cardtype = TYPE_PCI1753E;
+               }
+               pci_release_region(pcidev, PCIDIO_MAINREG);
        }
-       return NULL;
+       pci_disable_device(pcidev);
+       return cardtype;
 }
 
 static int pci_dio_auto_attach(struct comedi_device *dev,
-                                        unsigned long context_unused)
+                              unsigned long context)
 {
        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-       const struct dio_boardtype *this_board;
+       const struct dio_boardtype *this_board = NULL;
        struct pci_dio_private *devpriv;
        struct comedi_subdevice *s;
        int ret, subdev, i, j;
 
-       this_board = pci_dio_find_boardinfo(dev, pcidev);
+       if (context < ARRAY_SIZE(boardtypes))
+               this_board = &boardtypes[context];
        if (!this_board)
                return -ENODEV;
        dev->board_ptr = this_board;
@@ -1111,7 +1112,7 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
                return -ENOMEM;
        dev->private = devpriv;
 
-       ret = comedi_pci_enable(pcidev, dev->board_name);
+       ret = comedi_pci_enable(dev);
        if (ret)
                return ret;
        dev->iobase = pci_resource_start(pcidev, this_board->main_pci_region);
@@ -1172,7 +1173,6 @@ static int pci_dio_auto_attach(struct comedi_device *dev,
 static void pci_dio_detach(struct comedi_device *dev)
 {
        struct pci_dio_private *devpriv = dev->private;
-       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
        struct comedi_subdevice *s;
        int i;
 
@@ -1180,18 +1180,13 @@ static void pci_dio_detach(struct comedi_device *dev)
                if (devpriv->valid)
                        pci_dio_reset(dev);
        }
-       if (dev->subdevices) {
-               for (i = 0; i < dev->n_subdevices; i++) {
-                       s = &dev->subdevices[i];
-                       if (s->type == COMEDI_SUBD_DIO)
-                               subdev_8255_cleanup(dev, s);
-                       s->private = NULL;
-               }
-       }
-       if (pcidev) {
-               if (dev->iobase)
-                       comedi_pci_disable(pcidev);
+       for (i = 0; i < dev->n_subdevices; i++) {
+               s = &dev->subdevices[i];
+               if (s->type == COMEDI_SUBD_DIO)
+                       comedi_spriv_free(dev, i);
+               s->private = NULL; /* some private data is static */
        }
+       comedi_pci_disable(dev);
 }
 
 static struct comedi_driver adv_pci_dio_driver = {
@@ -1202,26 +1197,29 @@ static struct comedi_driver adv_pci_dio_driver = {
 };
 
 static int adv_pci_dio_pci_probe(struct pci_dev *dev,
-                                          const struct pci_device_id *ent)
+                                const struct pci_device_id *id)
 {
-       return comedi_pci_auto_config(dev, &adv_pci_dio_driver);
+       unsigned long cardtype;
+
+       cardtype = pci_dio_override_cardtype(dev, id->driver_data);
+       return comedi_pci_auto_config(dev, &adv_pci_dio_driver, cardtype);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(adv_pci_dio_pci_table) = {
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) },
-       { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) },
+       { PCI_VDEVICE(ADVANTECH, 0x1730), TYPE_PCI1730 },
+       { PCI_VDEVICE(ADVANTECH, 0x1733), TYPE_PCI1733 },
+       { PCI_VDEVICE(ADVANTECH, 0x1734), TYPE_PCI1734 },
+       { PCI_VDEVICE(ADVANTECH, 0x1735), TYPE_PCI1735 },
+       { PCI_VDEVICE(ADVANTECH, 0x1736), TYPE_PCI1736 },
+       { PCI_VDEVICE(ADVANTECH, 0x1739), TYPE_PCI1739 },
+       { PCI_VDEVICE(ADVANTECH, 0x1750), TYPE_PCI1750 },
+       { PCI_VDEVICE(ADVANTECH, 0x1751), TYPE_PCI1751 },
+       { PCI_VDEVICE(ADVANTECH, 0x1752), TYPE_PCI1752 },
+       { PCI_VDEVICE(ADVANTECH, 0x1753), TYPE_PCI1753 },
+       { PCI_VDEVICE(ADVANTECH, 0x1754), TYPE_PCI1754 },
+       { PCI_VDEVICE(ADVANTECH, 0x1756), TYPE_PCI1756 },
+       { PCI_VDEVICE(ADVANTECH, 0x1760), TYPE_PCI1760 },
+       { PCI_VDEVICE(ADVANTECH, 0x1762), TYPE_PCI1762 },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table);