An common module used for all of module communication.

The module encapsule a group of notification,
used for decoupling between modules, for example,
the touchscreen driver are coupling fingerprint
and display driver in the bring-up phase,
the dependencies between modules need to fixed
to avoid proceeding blocked,
This module is middle layer, it change a direct
dependece into an indirect dependence.

Change-Id: I4469dd70300fce2dc5d9af48e96d65755974ef9f
Reviewed-on: https://gerrit.mot.com/1802936
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Reviewed-by: Sergio Vilela <sv008@motorola.com>
Submit-Approved: Sergio Vilela <sv008@motorola.com>
Tested-by: Sergio Vilela <sv008@motorola.com>
This commit is contained in:
litong 2020-11-12 15:24:58 +08:00 • committed by Sergio Vilela
commit 5d385bce9d
5 changed files with 289 additions and 0 deletions

View file

@ -0,0 +1,12 @@
DLKM_DIR := motorola/kernel/modules
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := mmi_relay.ko
LOCAL_MODULE_TAGS := optional
ifeq ($(DLKM_INSTALL_TO_VENDOR_OUT),true)
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/
else
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
endif
include $(DLKM_DIR)/AndroidKernelModule.mk

5
drivers/mmi_relay/Kbuild Normal file
View file

@ -0,0 +1,5 @@
# add -Wall to try to catch everything we can.
EXTRA_CFLAGS += -Wall
EXTRA_CFLAGS += -I$(ANDROID_BUILD_TOP)/motorola/kernel/modules/include
obj-m += mmi_relay.o

View file

@ -0,0 +1,10 @@
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
modules_install:
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
clean:
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean

View file

@ -0,0 +1,234 @@
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/workqueue.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/mmi_relay.h>
#include <linux/slab.h>
typedef struct _relay_node {
struct list_head list;
union {
struct atomic_notifier_head atomic_head;
struct blocking_notifier_head blocking_head;
};
int id;
notifier_t type;
notifier_d dev;
}relay_node;
struct mmi_relay_dev {
struct platform_device *pdev;
struct mutex lock;
relay_node nodes[NUM_TYPES][NUM_DEVS];
unsigned notifier_nums;
};
static struct mmi_relay_dev* relay_dev;
/*
* Informs the registered notifiers about an event
* @type: notification type: atomic blocking
* @dev: notification sender
* @val: value passed to notifier function
*/
int relay_notifier_fire(notifier_t type, notifier_d dev, unsigned long val, void *v)
{
int ret = 0;
if(!relay_dev) {
pr_err("Device is not initialized\n");
return -EINVAL;
}
if(type >= NUM_TYPES || dev >= NUM_DEVS) {
pr_err("Relay error type or dev\n");
return -EPERM;
}
switch(type) {
case ATOMIC:
{
struct atomic_notifier_head* h = &relay_dev->nodes[type][dev].atomic_head;
ret = atomic_notifier_call_chain(h, val, v);
break;
}
case BLOCKING:
{
struct blocking_notifier_head* h = &relay_dev->nodes[type][dev].blocking_head;
ret = blocking_notifier_call_chain(h, val, v);
break;
}
default:
BUG_ON(1);
}
return ret;
}
EXPORT_SYMBOL_GPL(relay_notifier_fire);
/**
* Register an atomic or blocking notify to receive notifications from dev.
* @dev: notification sender
*/
int relay_register_action(notifier_t type, notifier_d dev, struct notifier_block * nb)
{
int ret = 0;
if(!relay_dev) {
pr_err("Device is not initialized\n");
return -EINVAL;
}
if(type >= NUM_TYPES || dev >= NUM_DEVS) {
pr_err("Relay error type or dev\n");
return -EPERM;
}
mutex_lock(&relay_dev->lock);
switch(type) {
case ATOMIC:
{
struct atomic_notifier_head* h = &relay_dev->nodes[type][dev].atomic_head;
ret = atomic_notifier_chain_register(h, nb);
if (!ret)
relay_notifier_fire(ATOMIC, MMI_RELAY, RELAY_NOTIFY_REGISTER, NULL);
break;
}
case BLOCKING:
{
struct blocking_notifier_head* h = &relay_dev->nodes[type][dev].blocking_head;
ret = blocking_notifier_chain_register(h, nb);
if (!ret)
relay_notifier_fire(BLOCKING, MMI_RELAY, RELAY_NOTIFY_REGISTER, NULL);
break;
}
default:
BUG_ON(1);
}
mutex_unlock(&relay_dev->lock);
return ret;
}
EXPORT_SYMBOL_GPL(relay_register_action);
int relay_unregister_action(notifier_t type, notifier_d dev, struct notifier_block *nb)
{
int ret = 0;
if(!relay_dev) {
pr_err("Device is not initialized\n");
return -EINVAL;
}
if(type >= NUM_TYPES || dev >= NUM_DEVS) {
pr_err("Relay error type or dev\n");
return -EPERM;
}
mutex_lock(&relay_dev->lock);
switch(type) {
case ATOMIC:
{
struct atomic_notifier_head* h = &relay_dev->nodes[type][dev].atomic_head;
ret = atomic_notifier_chain_unregister(h, nb);
if (!ret)
relay_notifier_fire(ATOMIC, MMI_RELAY, RELAY_NOTIFY_UNREGISTER, NULL);
break;
}
case BLOCKING:
{
struct blocking_notifier_head* h = &relay_dev->nodes[type][dev].blocking_head;
ret = blocking_notifier_chain_unregister(h, nb);
if (!ret)
relay_notifier_fire(BLOCKING, MMI_RELAY, RELAY_NOTIFY_UNREGISTER, NULL);
break;
}
default:
BUG_ON(1);
}
mutex_unlock(&relay_dev->lock);
return ret;
}
EXPORT_SYMBOL_GPL(relay_unregister_action);
static int mmi_relay_probe(struct platform_device *pdev)
{
notifier_t i;
notifier_d j;
relay_dev = kzalloc(sizeof(struct mmi_relay_dev), GFP_KERNEL);
if (!relay_dev) {
pr_err("Failed to allocate memory for relay_dev\n");
return -ENOMEM;
}
relay_dev->pdev = pdev;
relay_dev->notifier_nums = NUM_DEVS * NUM_TYPES;
mutex_init(&relay_dev->lock);
for(i = (notifier_t)0; i < NUM_TYPES; i++) {
for(j = (notifier_d)0; j < NUM_DEVS; j++) {
relay_dev->nodes[i][j].type = i;
relay_dev->nodes[i][j].dev= j;
relay_dev->nodes[i][j].id = i << 16 | j;
INIT_LIST_HEAD(&relay_dev->nodes[i][j].list);
if(i == ATOMIC) {
ATOMIC_INIT_NOTIFIER_HEAD(&relay_dev->nodes[i][j].atomic_head);
} else {
BLOCKING_INIT_NOTIFIER_HEAD(&relay_dev->nodes[i][j].blocking_head);
}
}
}
return 0;
}
static int mmi_relay_remove(struct platform_device *pdev)
{
kfree(relay_dev);
return 0;
}
static const struct of_device_id mmi_relay_mt[] = {
{.compatible = "mmi,sys-relay"},
{},
};
MODULE_DEVICE_TABLE(of, mmi_relay_mt);
static struct platform_driver mmi_relay_driver = {
.probe = mmi_relay_probe,
.remove = mmi_relay_remove,
.driver = {
.name = "mmi_relay",
.owner = THIS_MODULE,
.of_match_table = mmi_relay_mt,
},
};
static int __init mmi_relay_init(void)
{
return platform_driver_register(&mmi_relay_driver);
}
static void __exit mmi_relay_exit(void)
{
platform_driver_unregister(&mmi_relay_driver);
}
module_init(mmi_relay_init);
module_exit(mmi_relay_exit);
MODULE_ALIAS("platform:mmi_relay");
MODULE_AUTHOR("Motorola Mobility LLC");
MODULE_DESCRIPTION("Motorola Mobility Module Conmmunication Relay");
MODULE_LICENSE("GPL");

28
include/linux/mmi_relay.h Normal file
View file

@ -0,0 +1,28 @@
#ifndef __MMI_RELAY_H__
#define __MMI_RELAY_H__
#include <linux/notifier.h>
typedef enum notifier_type {
ATOMIC,
BLOCKING,
NUM_TYPES,
}notifier_t;
typedef enum notifier_dev {
LCD,
FPS,
MMI_RELAY,
NUM_DEVS,
}notifier_d;
enum mmi_relay_event {
RELAY_NOTIFY_REGISTER,
RELAY_NOTIFY_UNREGISTER,
};
extern int relay_notifier_fire(notifier_t type, notifier_d dev, unsigned long val, void *v);
extern int relay_register_action(notifier_t type, notifier_d dev, struct notifier_block * nb);
extern int relay_unregister_action(notifier_t type, notifier_d dev, struct notifier_block * nb);
#endif