// SPDX-License-Identifier: GPL-2.0
/*
* Copyright � 2010 - 2015 UNISYS CORPORATION
* All rights reserved.
*/
#include <linux/ctype.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/visorbus.h>
#include <linux/uuid.h>
#include "visorbus_private.h"
static const guid_t visor_vbus_channel_guid = VISOR_VBUS_CHANNEL_GUID;
/* Display string that is guaranteed to be no longer the 99 characters */
#define LINESIZE 99
#define POLLJIFFIES_NORMALCHANNEL 10
/* stores whether bus_registration was successful */
static bool initialized;
static struct dentry *visorbus_debugfs_dir;
/*
* DEVICE type attributes
*
* The modalias file will contain the guid of the device.
*/
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct visor_device *vdev;
const guid_t *guid;
vdev = to_visor_device(dev);
guid = visorchannel_get_guid(vdev->visorchannel);
return sprintf(buf, "visorbus:%pUl\n", guid);
}
static DEVICE_ATTR_RO(modalias);
static struct attribute *visorbus_dev_attrs[] = {
&dev_attr_modalias.attr,
NULL,
};
ATTRIBUTE_GROUPS(visorbus_dev);
/* filled in with info about parent chipset driver when we register with it */
static struct visor_vbus_deviceinfo chipset_driverinfo;
/* filled in with info about this driver, wrt it servicing client busses */
static struct visor_vbus_deviceinfo clientbus_driverinfo;
/* list of visor_device structs, linked via .list_all */
static LIST_HEAD(list_all_bus_instances);
/* list of visor_device structs, linked via .list_all */
static LIST_HEAD(list_all_device_instances);
/*
* Generic function useful for validating any type of channel when it is
* received by the client that will be accessing the channel.
* Note that <logCtx> is only needed for callers in the EFI environment, and
* is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages.
*/
int visor_check_channel(struct channel_header *ch, struct device *dev,
const guid_t *expected_guid, char *chname,
u64 expected_min_bytes, u32 expected_version,
u64 expected_signature)
{
if (!guid_is_null(expected_guid)) {
/* caller wants us to verify type GUID */
if (!guid_equal(&ch->chtype, expected_guid)) {
dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=type expected=%pUL actual=%pUL\n",
chname, expected_guid, expected_guid,
&ch->chtype);
return 0;
}
}
/* verify channel size */
if (expected_min_bytes > 0) {
if (ch->size < expected_min_bytes) {
dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=size expected=0x%-8.8Lx actual=0x%-8.8Lx\n",
chname, expected_guid,
(unsigned long long)expected_min_bytes,
ch->size);
return 0;
}
}
/* verify channel version */
if (expected_version > 0) {
if (ch->version_id != expected_version) {
dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=version expected=0x%-8.8lx actual=0x%-8.8x\n",
chname, expected_guid,
(unsigned long)expected_version,
ch->version_id);
return 0;
}
}
/* verify channel signature */
if (expected_signature > 0) {
if (ch->signature != expected_signature) {
dev_err(dev, "Channel mismatch on channel=%s(%pUL) field=signature expected=0x%-8.8Lx actual=0x%-8.8Lx\n",
chname, expected_guid, expected_signature,
ch->signature);
return 0;
}
}
return 1;
}
static int visorbus_uevent(struct device *xdev, struct kobj_uevent_env *env)
{
struct visor_device *dev;
const guid_t *guid;
dev = to_visor_device(xdev);
guid = visorchannel_get_guid(dev->visorchannel);
return add_uevent_var(env, "MODALIAS=visorbus:%pUl", guid);
}
/*
* visorbus_match() - called automatically upon adding a visor_device
* (device_add), or adding a visor_driver
* (visorbus_register_visor_driver)
* @xdev: struct device for the device being matched
* @xdrv: struct device_driver for driver to match device against
*
* Return: 1 iff the provided driver can control the specified device
*/
static int visorbus_match(struct device *xdev, struct de