@@ -59,6 +59,82 @@ int port_feature_num(void)
return PORT_FEATURE_ID_MAX;
}
+struct fpga_chardev_info {
+ const char *name;
+ dev_t devt;
+};
+
+/* indexed by enum fpga_devt_type */
+struct fpga_chardev_info fpga_chrdevs[] = {
+ {.name = FPGA_FEATURE_DEV_FME}, /* FPGA_DEVT_FME */
+ {.name = FPGA_FEATURE_DEV_PORT}, /* FPGA_DEVT_AFU */
+};
+
+void fpga_chardev_uinit(void)
+{
+ int i;
+
+ for (i = 0; i < FPGA_DEVT_MAX; i++)
+ if (MAJOR(fpga_chrdevs[i].devt)) {
+ unregister_chrdev_region(fpga_chrdevs[i].devt,
+ MINORMASK);
+ fpga_chrdevs[i].devt = MKDEV(0, 0);
+ }
+}
+
+int fpga_chardev_init(void)
+{
+ int i, ret;
+
+ for (i = 0; i < FPGA_DEVT_MAX; i++) {
+ ret = alloc_chrdev_region(&fpga_chrdevs[i].devt, 0, MINORMASK,
+ fpga_chrdevs[i].name);
+ if (ret)
+ goto exit;
+ }
+
+ return 0;
+
+exit:
+ fpga_chardev_uinit();
+ return ret;
+}
+
+dev_t fpga_get_devt(enum fpga_devt_type type, int id)
+{
+ WARN_ON(type >= FPGA_DEVT_MAX);
+
+ return MKDEV(MAJOR(fpga_chrdevs[type].devt), id);
+}
+
+int fpga_register_dev_ops(struct platform_device *pdev,
+ const struct file_operations *fops,
+ struct module *owner)
+{
+ struct feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+ cdev_init(&pdata->cdev, fops);
+ pdata->cdev.owner = owner;
+
+ /*
+ * set parent to the feature device so that its refcount is
+ * decreased after the last refcount of cdev is gone, that
+ * makes sure the feature device is valid during device
+ * file's life-cycle.
+ */
+ pdata->cdev.kobj.parent = &pdev->dev.kobj;
+ return cdev_add(&pdata->cdev, pdev->dev.devt, 1);
+}
+EXPORT_SYMBOL_GPL(fpga_register_dev_ops);
+
+void fpga_unregister_dev_ops(struct platform_device *pdev)
+{
+ struct feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+ cdev_del(&pdata->cdev);
+}
+EXPORT_SYMBOL_GPL(fpga_unregister_dev_ops);
+
int fpga_port_id(struct platform_device *pdev)
{
struct feature_port_header *port_hdr;
@@ -19,6 +19,7 @@
#define __INTEL_FPGA_FEATURE_H
#include <linux/fs.h>
+#include <linux/cdev.h>
#include <linux/pci.h>
#include <linux/uuid.h>
#include <linux/delay.h>
@@ -216,6 +217,7 @@ struct feature_platform_data {
/* list the feature dev to cci_drvdata->port_dev_list. */
struct list_head node;
struct mutex lock;
+ struct cdev cdev;
struct platform_device *dev;
unsigned int disable_count; /* count for port disable */
@@ -256,6 +258,20 @@ int feature_platform_data_size(int num);
struct feature_platform_data *
feature_platform_data_alloc_and_init(struct platform_device *dev, int num);
+enum fpga_devt_type {
+ FPGA_DEVT_FME,
+ FPGA_DEVT_PORT,
+ FPGA_DEVT_MAX,
+};
+
+void fpga_chardev_uinit(void);
+int fpga_chardev_init(void);
+dev_t fpga_get_devt(enum fpga_devt_type type, int id);
+int fpga_register_dev_ops(struct platform_device *pdev,
+ const struct file_operations *fops,
+ struct module *owner);
+void fpga_unregister_dev_ops(struct platform_device *pdev);
+
int fpga_port_id(struct platform_device *pdev);
static inline int fpga_port_check_id(struct platform_device *pdev,
@@ -276,8 +276,12 @@ build_info_create_dev(struct build_feature_devs_info *binfo,
struct platform_device *fdev;
struct resource *res;
struct feature_platform_data *pdata;
+ enum fpga_devt_type devt_type = FPGA_DEVT_FME;
int ret;
+ if (type == PORT_ID)
+ devt_type = FPGA_DEVT_PORT;
+
/* we will create a new device, commit current device first */
ret = build_info_commit_dev(binfo);
if (ret)
@@ -296,6 +300,7 @@ build_info_create_dev(struct build_feature_devs_info *binfo,
return fdev->id;
fdev->dev.parent = &binfo->parent_dev->dev;
+ fdev->dev.devt = fpga_get_devt(devt_type, fdev->id);
/*
* we need not care the memory which is associated with the
@@ -945,16 +950,27 @@ static int __init ccidrv_init(void)
fpga_ids_init();
+ ret = fpga_chardev_init();
+ if (ret)
+ goto exit_ids;
+
ret = pci_register_driver(&cci_pci_driver);
if (ret)
- fpga_ids_destroy();
+ goto exit_chardev;
+ return 0;
+
+exit_chardev:
+ fpga_chardev_uinit();
+exit_ids:
+ fpga_ids_destroy();
return ret;
}
static void __exit ccidrv_exit(void)
{
pci_unregister_driver(&cci_pci_driver);
+ fpga_chardev_uinit();
fpga_ids_destroy();
}