lineage_kernel_xcoverpro/drivers/misc/samsung/scsc/pcie_mif_module.c

191 lines
5.4 KiB
C
Executable File

#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <scsc/scsc_logring.h>
#include "pcie_mif_module.h"
#include "pcie_mif.h"
/* Implements */
#include "scsc_mif_abs.h"
struct mif_abs_node {
struct list_head list;
struct scsc_mif_abs *mif_abs;
};
struct mif_driver_node {
struct list_head list;
struct scsc_mif_abs_driver *driver; /* list of drivers (in practice just the core_module) */
};
struct mif_mmap_node {
struct list_head list;
struct scsc_mif_mmap_driver *driver; /* list of drivers (in practive just the core_module) */
};
static struct pcie_mif_module {
struct list_head mif_abs_list;
struct list_head mif_driver_list;
struct list_head mif_mmap_list;
} mif_module = {
.mif_abs_list = LIST_HEAD_INIT(mif_module.mif_abs_list),
.mif_driver_list = LIST_HEAD_INIT(mif_module.mif_driver_list),
.mif_mmap_list = LIST_HEAD_INIT(mif_module.mif_mmap_list),
};
static const struct pci_device_id pcie_mif_module_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_SAMSUNG_SCSC) },
{ /*End: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, pcie_mif_module_tbl);
static void pcie_mif_module_probe_registered_clients(struct scsc_mif_abs *mif_abs)
{
struct mif_driver_node *mif_driver_node, *next;
struct device *dev;
bool driver_registered = false;
/* Traverse Linked List for each mif_driver node */
list_for_each_entry_safe(mif_driver_node, next, &mif_module.mif_driver_list, list) {
SCSC_TAG_INFO(PCIE_MIF, "node %p\n", mif_driver_node);
dev = pcie_mif_get_dev(mif_abs);
mif_driver_node->driver->probe(mif_driver_node->driver, mif_abs);
driver_registered = true;
}
if (driver_registered == false)
SCSC_TAG_INFO(PCIE_MIF, "No mif drivers registered\n");
}
static int pcie_mif_module_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct mif_abs_node *mif_node;
struct scsc_mif_abs *mif_abs;
mif_node = kzalloc(sizeof(*mif_node), GFP_KERNEL);
if (!mif_node)
return -ENODEV;
mif_abs = pcie_mif_create(pdev, id);
if (!mif_abs) {
SCSC_TAG_INFO(PCIE_MIF, "Error creating PCIe interface\n");
kfree(mif_node);
return -ENODEV;
}
/* Add node */
mif_node->mif_abs = mif_abs;
SCSC_TAG_INFO(PCIE_MIF, "mif_node A %p\n", mif_node);
list_add_tail(&mif_node->list, &mif_module.mif_abs_list);
pcie_mif_module_probe_registered_clients(mif_abs);
return 0;
}
static void pcie_mif_module_remove(struct pci_dev *pdev)
{
struct mif_abs_node *mif_node, *next;
bool match = false;
/* Remove node */
list_for_each_entry_safe(mif_node, next, &mif_module.mif_abs_list, list) {
if (pcie_mif_get_pci_dev(mif_node->mif_abs) == pdev) {
match = true;
SCSC_TAG_INFO(PCIE_MIF, "Match, destroy pcie_mif\n");
pcie_mif_destroy_pcie(pdev, mif_node->mif_abs);
list_del(&mif_node->list);
kfree(mif_node);
}
}
if (match == false)
SCSC_TAG_INFO(PCIE_MIF, "FATAL, no match for given scsc_mif_abs\n");
}
static struct pci_driver scsc_pcie = {
.name = DRV_NAME,
.id_table = pcie_mif_module_tbl,
.probe = pcie_mif_module_probe,
.remove = pcie_mif_module_remove,
};
void scsc_mif_abs_register(struct scsc_mif_abs_driver *driver)
{
struct mif_driver_node *mif_driver_node;
struct mif_abs_node *mif_node;
struct device *dev;
/* Add node in driver linked list */
mif_driver_node = kzalloc(sizeof(*mif_driver_node), GFP_KERNEL);
if (!mif_driver_node)
return;
mif_driver_node->driver = driver;
list_add_tail(&mif_driver_node->list, &mif_module.mif_driver_list);
/* Traverse Linked List for each mif_abs node */
list_for_each_entry(mif_node, &mif_module.mif_abs_list, list) {
dev = pcie_mif_get_dev(mif_node->mif_abs);
driver->probe(driver, mif_node->mif_abs);
}
}
EXPORT_SYMBOL(scsc_mif_abs_register);
void scsc_mif_abs_unregister(struct scsc_mif_abs_driver *driver)
{
struct mif_driver_node *mif_driver_node, *next;
/* Traverse Linked List for each mif_driver node */
list_for_each_entry_safe(mif_driver_node, next, &mif_module.mif_driver_list, list) {
if (mif_driver_node->driver == driver) {
list_del(&mif_driver_node->list);
kfree(mif_driver_node);
}
}
}
EXPORT_SYMBOL(scsc_mif_abs_unregister);
/* Register a mmap - debug driver - for this specific transport*/
void scsc_mif_mmap_register(struct scsc_mif_mmap_driver *mmap_driver)
{
struct mif_mmap_node *mif_mmap_node;
struct mif_abs_node *mif_node;
/* Add node in driver linked list */
mif_mmap_node = kzalloc(sizeof(*mif_mmap_node), GFP_KERNEL);
if (!mif_mmap_node)
return;
mif_mmap_node->driver = mmap_driver;
list_add_tail(&mif_mmap_node->list, &mif_module.mif_mmap_list);
/* Traverse Linked List for each mif_abs node */
list_for_each_entry(mif_node, &mif_module.mif_abs_list, list) {
mmap_driver->probe(mmap_driver, mif_node->mif_abs);
}
}
EXPORT_SYMBOL(scsc_mif_mmap_register);
/* Unregister a mmap - debug driver - for this specific transport*/
void scsc_mif_mmap_unregister(struct scsc_mif_mmap_driver *mmap_driver)
{
struct mif_mmap_node *mif_mmap_node, *next;
/* Traverse Linked List for each mif_mmap_driver node */
list_for_each_entry_safe(mif_mmap_node, next, &mif_module.mif_mmap_list, list) {
if (mif_mmap_node->driver == mmap_driver) {
list_del(&mif_mmap_node->list);
kfree(mif_mmap_node);
}
}
}
EXPORT_SYMBOL(scsc_mif_mmap_unregister);
module_pci_driver(scsc_pcie);
MODULE_DESCRIPTION("SLSI PCIe mx140 MIF abstraction");
MODULE_AUTHOR("SLSI");
MODULE_LICENSE("GPL");