staging: unisys: add visorbus driver
This base driver provides bus functionality to visorhid, visorhba, and visornic which will be later added to our driver base. Visorbus supports sPar bus model and manages bus specific functionality. It maintains the sysfs subtree /sys/devices/visorbus*/.It is responsible for device creation and destruction of the devices on its bus. Signed-off-by: Erik Arfvidson <erik.arfvidson@unisys.com> Signed-off-by: Benjamin Romer <benjamin.romer@unisys.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
7e61e4c9b3
commit
3703987cd4
|
@ -12,5 +12,6 @@ if UNISYSSPAR
|
|||
source "drivers/staging/unisys/visorutil/Kconfig"
|
||||
source "drivers/staging/unisys/visorchannel/Kconfig"
|
||||
source "drivers/staging/unisys/visorchipset/Kconfig"
|
||||
source "drivers/staging/unisys/visorbus/Kconfig"
|
||||
|
||||
endif # UNISYSSPAR
|
||||
|
|
|
@ -4,3 +4,4 @@
|
|||
obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil/
|
||||
obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel/
|
||||
obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset/
|
||||
obj-$(CONFIG_UNISYS_VISORBUS) += visorbus/
|
||||
|
|
|
@ -54,7 +54,7 @@ static const uuid_le spar_vbus_channel_protocol_uuid =
|
|||
#define SPAR_VBUS_CHANNEL_OK_SERVER(actual_bytes) \
|
||||
(spar_check_channel_server(spar_vbus_channel_protocol_uuid, \
|
||||
"vbus", \
|
||||
sizeof(struct ultra_vbus_channel_protocol),\
|
||||
sizeof(struct spar_vbus_channel_protocol),\
|
||||
actual_bytes))
|
||||
|
||||
#pragma pack(push, 1) /* both GCC and VC now allow this pragma */
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
#
|
||||
# Unisys visorbus configuration
|
||||
#
|
||||
|
||||
config UNISYS_VISORBUS
|
||||
tristate "Unisys visorbus driver"
|
||||
depends on UNISYSSPAR && UNISYS_VISORUTIL && UNISYS_VISORCHANNEL && UNISYS_VISORCHIPSET
|
||||
---help---
|
||||
If you say Y here, you will enable the Unisys visorbus driver.
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Makefile for Unisys visorbus
|
||||
#
|
||||
|
||||
obj-$(CONFIG_UNISYS_VISORBUS) += visorbus.o
|
||||
|
||||
visorbus-y := visorbus_main.o devmajorminor_attr.o businst_attr.o channel_attr.o
|
||||
|
||||
ccflags-y += -Idrivers/staging/unisys/include
|
||||
ccflags-y += -Idrivers/staging/unisys/visorchannel
|
||||
ccflags-y += -Idrivers/staging/unisys/visorchipset
|
||||
ccflags-y += -Idrivers/staging/unisys/common-spar/include
|
||||
ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
|
||||
ccflags-y += -Idrivers/staging/unisys/visorutil
|
|
@ -0,0 +1,103 @@
|
|||
/* businst_attr.c
|
||||
*
|
||||
* Copyright (C) 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/* This is actually something they forgot to put in the kernel.
|
||||
* struct bus_type in the kernel SHOULD have a "busses" member, which
|
||||
* should be treated similarly to the "devices" and "drivers" members.
|
||||
* There SHOULD be:
|
||||
* - a "businst_attribute" analogous to the existing "bus_attribute"
|
||||
* - a "businst_create_file" and "businst_remove_file" analogous to the
|
||||
* existing "bus_create_file" and "bus_remove_file".
|
||||
* That's what I created businst.c and businst.h to do.
|
||||
*
|
||||
* We want to add the "busses" sub-tree in sysfs, where we will house the
|
||||
* names and properties of each bus instance:
|
||||
*
|
||||
* /sys/bus/<bustypename>/
|
||||
* version
|
||||
* devices
|
||||
* <devname1> --> /sys/devices/<businstancename><devname1>
|
||||
* <devname2> --> /sys/devices/<businstancename><devname2>
|
||||
* drivers
|
||||
* <driverinstancename1>
|
||||
* <driverinstance1property1>
|
||||
* <driverinstance1property2>
|
||||
* ...
|
||||
* <driverinstancename2>
|
||||
* <driverinstance2property1>
|
||||
* <driverinstance2property2>
|
||||
* ...
|
||||
* >> busses
|
||||
* >> <businstancename1>
|
||||
* >> <businstance1property1>
|
||||
* >> <businstance1property2>
|
||||
* >> ...
|
||||
* >> <businstancename2>
|
||||
* >> <businstance2property1>
|
||||
* >> <businstance2property2>
|
||||
* >> ...
|
||||
*
|
||||
* I considered adding bus instance properties under
|
||||
* /sys/devices/<businstancename>. But I thought there may be existing
|
||||
* notions that ONLY device sub-trees should live under
|
||||
* /sys/devices/<businstancename>. So I stayed out of there.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "businst_attr.h"
|
||||
|
||||
#define to_businst_attr(_attr) \
|
||||
container_of(_attr, struct businst_attribute, attr)
|
||||
#define to_visorbus_devdata(obj) \
|
||||
container_of(obj, struct visorbus_devdata, kobj)
|
||||
#define CURRENT_FILE_PC VISOR_BUS_PC_businst_attr_c
|
||||
|
||||
ssize_t businst_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct businst_attribute *businst_attr = to_businst_attr(attr);
|
||||
struct visorbus_devdata *bus = to_visorbus_devdata(kobj);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (businst_attr->show)
|
||||
ret = businst_attr->show(bus, buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ssize_t businst_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct businst_attribute *businst_attr = to_businst_attr(attr);
|
||||
struct visorbus_devdata *bus = to_visorbus_devdata(kobj);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (businst_attr->store)
|
||||
ret = businst_attr->store(bus, buf, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int businst_create_file(struct visorbus_devdata *bus,
|
||||
struct businst_attribute *attr)
|
||||
{
|
||||
return sysfs_create_file(&bus->kobj, &attr->attr);
|
||||
}
|
||||
|
||||
void businst_remove_file(struct visorbus_devdata *bus,
|
||||
struct businst_attribute *attr)
|
||||
{
|
||||
sysfs_remove_file(&bus->kobj, &attr->attr);
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/* businst_attr.h
|
||||
*
|
||||
* Copyright (C) 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
#ifndef __BUSINST_H__
|
||||
#define __BUSINST_H__
|
||||
|
||||
#include "visorbus_private.h" /* just to get visorbus_devdata declaration */
|
||||
#include "timskmod.h"
|
||||
|
||||
struct businst_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct visorbus_devdata*, char *buf);
|
||||
ssize_t (*store)(struct visorbus_devdata*, const char *buf,
|
||||
size_t count);
|
||||
};
|
||||
|
||||
ssize_t businst_attr_show(struct kobject *kobj,
|
||||
struct attribute *attr, char *buf);
|
||||
ssize_t businst_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
int businst_create_file(struct visorbus_devdata *bus,
|
||||
struct businst_attribute *attr);
|
||||
void businst_remove_file(struct visorbus_devdata *bus,
|
||||
struct businst_attribute *attr);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,227 @@
|
|||
/* channel_attr.c
|
||||
*
|
||||
* Copyright (C) 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/* Implement publishing of channel attributes under:
|
||||
*
|
||||
* /sys/bus/visorbus<x>/dev<y>/channel
|
||||
*
|
||||
*/
|
||||
|
||||
#include "channel_attr.h"
|
||||
#define CURRENT_FILE_PC VISOR_BUS_PC_channel_attr_c
|
||||
#define to_channel_attr(_attr) \
|
||||
container_of(_attr, struct channel_attribute, attr)
|
||||
#define to_visor_device_from_kobjchannel(obj) \
|
||||
container_of(obj, struct visor_device, kobjchannel)
|
||||
|
||||
struct channel_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct visor_device*, char *buf);
|
||||
ssize_t (*store)(struct visor_device*, const char *buf, size_t count);
|
||||
};
|
||||
|
||||
/* begin implementation of specific channel attributes to appear under
|
||||
* /sys/bus/visorbus<x>/dev<y>/channel
|
||||
*/
|
||||
static ssize_t devicechannel_attr_physaddr(struct visor_device *dev, char *buf)
|
||||
{
|
||||
if (!dev->visorchannel)
|
||||
return 0;
|
||||
return snprintf(buf, PAGE_SIZE, "0x%Lx\n",
|
||||
visorchannel_get_physaddr(dev->visorchannel));
|
||||
}
|
||||
|
||||
static ssize_t devicechannel_attr_nbytes(struct visor_device *dev, char *buf)
|
||||
{
|
||||
if (!dev->visorchannel)
|
||||
return 0;
|
||||
return snprintf(buf, PAGE_SIZE, "0x%lx\n",
|
||||
visorchannel_get_nbytes(dev->visorchannel));
|
||||
}
|
||||
|
||||
static ssize_t devicechannel_attr_clientpartition(struct visor_device *dev,
|
||||
char *buf) {
|
||||
if (!dev->visorchannel)
|
||||
return 0;
|
||||
return snprintf(buf, PAGE_SIZE, "0x%Lx\n",
|
||||
visorchannel_get_clientpartition(dev->visorchannel));
|
||||
}
|
||||
|
||||
static ssize_t devicechannel_attr_typeguid(struct visor_device *dev, char *buf)
|
||||
{
|
||||
char s[99];
|
||||
|
||||
if (!dev->visorchannel)
|
||||
return 0;
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
visorchannel_id(dev->visorchannel, s));
|
||||
}
|
||||
|
||||
static ssize_t devicechannel_attr_zoneguid(struct visor_device *dev, char *buf)
|
||||
{
|
||||
char s[99];
|
||||
|
||||
if (!dev->visorchannel)
|
||||
return 0;
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
visorchannel_zoneid(dev->visorchannel, s));
|
||||
}
|
||||
|
||||
static ssize_t devicechannel_attr_typename(struct visor_device *dev, char *buf)
|
||||
{
|
||||
int i = 0;
|
||||
struct bus_type *xbus = dev->device.bus;
|
||||
struct device_driver *xdrv = dev->device.driver;
|
||||
struct visor_driver *drv = NULL;
|
||||
|
||||
if (!dev->visorchannel || !xbus || !xdrv)
|
||||
return 0;
|
||||
i = xbus->match(&dev->device, xdrv);
|
||||
if (!i)
|
||||
return 0;
|
||||
drv = to_visor_driver(xdrv);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", drv->channel_types[i - 1].name);
|
||||
}
|
||||
|
||||
static ssize_t devicechannel_attr_dump(struct visor_device *dev, char *buf)
|
||||
{
|
||||
int count = 0;
|
||||
/* TODO: replace this with debugfs code
|
||||
struct seq_file *m = NULL;
|
||||
if (dev->visorchannel == NULL)
|
||||
return 0;
|
||||
m = visor_seq_file_new_buffer(buf, PAGE_SIZE - 1);
|
||||
if (m == NULL)
|
||||
return 0;
|
||||
visorchannel_debug(dev->visorchannel, 1, m, 0);
|
||||
count = m->count;
|
||||
visor_seq_file_done_buffer(m);
|
||||
m = NULL;
|
||||
*/
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct channel_attribute all_channel_attrs[] = {
|
||||
__ATTR(physaddr, S_IRUGO,
|
||||
devicechannel_attr_physaddr, NULL),
|
||||
__ATTR(nbytes, S_IRUGO,
|
||||
devicechannel_attr_nbytes, NULL),
|
||||
__ATTR(clientpartition, S_IRUGO,
|
||||
devicechannel_attr_clientpartition, NULL),
|
||||
__ATTR(typeguid, S_IRUGO,
|
||||
devicechannel_attr_typeguid, NULL),
|
||||
__ATTR(zoneguid, S_IRUGO,
|
||||
devicechannel_attr_zoneguid, NULL),
|
||||
__ATTR(typename, S_IRUGO,
|
||||
devicechannel_attr_typename, NULL),
|
||||
__ATTR(dump, S_IRUGO,
|
||||
devicechannel_attr_dump, NULL),
|
||||
};
|
||||
|
||||
/* end implementation of specific channel attributes */
|
||||
|
||||
static ssize_t channel_attr_show(struct kobject *kobj, struct attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct channel_attribute *channel_attr = to_channel_attr(attr);
|
||||
struct visor_device *dev = to_visor_device_from_kobjchannel(kobj);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (channel_attr->show)
|
||||
ret = channel_attr->show(dev, buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t channel_attr_store(struct kobject *kobj, struct attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct channel_attribute *channel_attr = to_channel_attr(attr);
|
||||
struct visor_device *dev = to_visor_device_from_kobjchannel(kobj);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (channel_attr->store)
|
||||
ret = channel_attr->store(dev, buf, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int channel_create_file(struct visor_device *dev,
|
||||
struct channel_attribute *attr)
|
||||
{
|
||||
return sysfs_create_file(&dev->kobjchannel, &attr->attr);
|
||||
}
|
||||
|
||||
static void channel_remove_file(struct visor_device *dev,
|
||||
struct channel_attribute *attr)
|
||||
{
|
||||
sysfs_remove_file(&dev->kobjchannel, &attr->attr);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops channel_sysfs_ops = {
|
||||
.show = channel_attr_show,
|
||||
.store = channel_attr_store,
|
||||
};
|
||||
|
||||
static struct kobj_type channel_kobj_type = {
|
||||
.sysfs_ops = &channel_sysfs_ops
|
||||
};
|
||||
|
||||
int register_channel_attributes(struct visor_device *dev)
|
||||
{
|
||||
int rc = 0, i = 0, x = 0;
|
||||
|
||||
if (dev->kobjchannel.parent)
|
||||
goto away; /* already registered */
|
||||
x = kobject_init_and_add(&dev->kobjchannel, &channel_kobj_type,
|
||||
&dev->device.kobj, "channel");
|
||||
if (x < 0) {
|
||||
rc = x;
|
||||
goto away;
|
||||
}
|
||||
|
||||
kobject_uevent(&dev->kobjchannel, KOBJ_ADD);
|
||||
|
||||
for (i = 0;
|
||||
i < sizeof(all_channel_attrs) / sizeof(struct channel_attribute);
|
||||
i++)
|
||||
x = channel_create_file(dev, &all_channel_attrs[i]);
|
||||
if (x < 0) {
|
||||
while (--i >= 0)
|
||||
channel_remove_file(dev, &all_channel_attrs[i]);
|
||||
kobject_del(&dev->kobjchannel);
|
||||
kobject_put(&dev->kobjchannel);
|
||||
rc = x;
|
||||
goto away;
|
||||
}
|
||||
away:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void unregister_channel_attributes(struct visor_device *dev)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
if (!dev->kobjchannel.parent)
|
||||
return; /* already unregistered */
|
||||
for (i = 0;
|
||||
i < sizeof(all_channel_attrs) / sizeof(struct channel_attribute);
|
||||
i++)
|
||||
channel_remove_file(dev, &all_channel_attrs[i]);
|
||||
|
||||
kobject_del(&dev->kobjchannel);
|
||||
kobject_put(&dev->kobjchannel);
|
||||
dev->kobjchannel.parent = NULL;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/* channel_attr.h
|
||||
*
|
||||
* Copyright (C) 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
#ifndef __CHANNEL_ATTR_H__
|
||||
#define __CHANNEL_ATTR_H__
|
||||
|
||||
#include "visorbus.h" /* just to get visor_device declaration */
|
||||
#include "timskmod.h"
|
||||
|
||||
int register_channel_attributes(struct visor_device *dev);
|
||||
void unregister_channel_attributes(struct visor_device *dev);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,192 @@
|
|||
/* devmajorminor_attr.c
|
||||
*
|
||||
* Copyright (C) 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/* Implement publishing of device node attributes under:
|
||||
*
|
||||
* /sys/bus/visorbus<x>/dev<y>/devmajorminor
|
||||
*
|
||||
*/
|
||||
|
||||
#include "devmajorminor_attr.h"
|
||||
#define CURRENT_FILE_PC VISOR_BUS_PC_devmajorminor_attr_c
|
||||
|
||||
#define to_devmajorminor_attr(_attr) \
|
||||
container_of(_attr, struct devmajorminor_attribute, attr)
|
||||
#define to_visor_device_from_kobjdevmajorminor(obj) \
|
||||
container_of(obj, struct visor_device, kobjdevmajorminor)
|
||||
|
||||
struct devmajorminor_attribute {
|
||||
struct attribute attr;
|
||||
int slot;
|
||||
ssize_t (*show)(struct visor_device *, int slot, char *buf);
|
||||
ssize_t (*store)(struct visor_device *, int slot, const char *buf,
|
||||
size_t count);
|
||||
};
|
||||
|
||||
static ssize_t DEVMAJORMINOR_ATTR(struct visor_device *dev, int slot, char *buf)
|
||||
{
|
||||
int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
|
||||
|
||||
if (slot < 0 || slot >= maxdevnodes)
|
||||
return 0;
|
||||
return snprintf(buf, PAGE_SIZE, "%d:%d\n",
|
||||
dev->devnodes[slot].major, dev->devnodes[slot].minor);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
devmajorminor_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
|
||||
{
|
||||
struct devmajorminor_attribute *devmajorminor_attr =
|
||||
to_devmajorminor_attr(attr);
|
||||
struct visor_device *dev = to_visor_device_from_kobjdevmajorminor(kobj);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (devmajorminor_attr->show)
|
||||
ret = devmajorminor_attr->show(dev,
|
||||
devmajorminor_attr->slot, buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
devmajorminor_attr_store(struct kobject *kobj,
|
||||
struct attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct devmajorminor_attribute *devmajorminor_attr =
|
||||
to_devmajorminor_attr(attr);
|
||||
struct visor_device *dev = to_visor_device_from_kobjdevmajorminor(kobj);
|
||||
ssize_t ret = 0;
|
||||
|
||||
if (devmajorminor_attr->store)
|
||||
ret = devmajorminor_attr->store(dev,
|
||||
devmajorminor_attr->slot,
|
||||
buf, count);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
devmajorminor_create_file(struct visor_device *dev, const char *name,
|
||||
int major, int minor)
|
||||
{
|
||||
int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
|
||||
struct devmajorminor_attribute *myattr = NULL;
|
||||
int x = -1, rc = 0, slot = -1;
|
||||
|
||||
register_devmajorminor_attributes(dev);
|
||||
for (slot = 0; slot < maxdevnodes; slot++)
|
||||
if (!dev->devnodes[slot].attr)
|
||||
break;
|
||||
if (slot == maxdevnodes) {
|
||||
rc = -ENOMEM;
|
||||
goto away;
|
||||
}
|
||||
myattr = kmalloc(sizeof(*myattr), GFP_KERNEL);
|
||||
if (!myattr) {
|
||||
rc = -ENOMEM;
|
||||
goto away;
|
||||
}
|
||||
memset(myattr, 0, sizeof(struct devmajorminor_attribute));
|
||||
myattr->show = DEVMAJORMINOR_ATTR;
|
||||
myattr->store = NULL;
|
||||
myattr->slot = slot;
|
||||
myattr->attr.name = name;
|
||||
myattr->attr.mode = S_IRUGO;
|
||||
dev->devnodes[slot].attr = myattr;
|
||||
dev->devnodes[slot].major = major;
|
||||
dev->devnodes[slot].minor = minor;
|
||||
x = sysfs_create_file(&dev->kobjdevmajorminor, &myattr->attr);
|
||||
if (x < 0) {
|
||||
rc = x;
|
||||
goto away;
|
||||
}
|
||||
kobject_uevent(&dev->device.kobj, KOBJ_ONLINE);
|
||||
away:
|
||||
if (rc < 0) {
|
||||
kfree(myattr);
|
||||
myattr = NULL;
|
||||
dev->devnodes[slot].attr = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
devmajorminor_remove_file(struct visor_device *dev, int slot)
|
||||
{
|
||||
int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
|
||||
struct devmajorminor_attribute *myattr = NULL;
|
||||
|
||||
if (slot < 0 || slot >= maxdevnodes)
|
||||
return;
|
||||
myattr = (struct devmajorminor_attribute *)(dev->devnodes[slot].attr);
|
||||
if (myattr)
|
||||
return;
|
||||
sysfs_remove_file(&dev->kobjdevmajorminor, &myattr->attr);
|
||||
kobject_uevent(&dev->device.kobj, KOBJ_OFFLINE);
|
||||
dev->devnodes[slot].attr = NULL;
|
||||
kfree(myattr);
|
||||
}
|
||||
|
||||
void
|
||||
devmajorminor_remove_all_files(struct visor_device *dev)
|
||||
{
|
||||
int i = 0;
|
||||
int maxdevnodes = ARRAY_SIZE(dev->devnodes) / sizeof(dev->devnodes[0]);
|
||||
|
||||
for (i = 0; i < maxdevnodes; i++)
|
||||
devmajorminor_remove_file(dev, i);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops devmajorminor_sysfs_ops = {
|
||||
.show = devmajorminor_attr_show,
|
||||
.store = devmajorminor_attr_store,
|
||||
};
|
||||
|
||||
static struct kobj_type devmajorminor_kobj_type = {
|
||||
.sysfs_ops = &devmajorminor_sysfs_ops
|
||||
};
|
||||
|
||||
int
|
||||
register_devmajorminor_attributes(struct visor_device *dev)
|
||||
{
|
||||
int rc = 0, x = 0;
|
||||
|
||||
if (dev->kobjdevmajorminor.parent)
|
||||
goto away; /* already registered */
|
||||
x = kobject_init_and_add(&dev->kobjdevmajorminor,
|
||||
&devmajorminor_kobj_type, &dev->device.kobj,
|
||||
"devmajorminor");
|
||||
if (x < 0) {
|
||||
rc = x;
|
||||
goto away;
|
||||
}
|
||||
|
||||
kobject_uevent(&dev->kobjdevmajorminor, KOBJ_ADD);
|
||||
|
||||
away:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
unregister_devmajorminor_attributes(struct visor_device *dev)
|
||||
{
|
||||
if (!dev->kobjdevmajorminor.parent)
|
||||
return; /* already unregistered */
|
||||
devmajorminor_remove_all_files(dev);
|
||||
|
||||
kobject_del(&dev->kobjdevmajorminor);
|
||||
kobject_put(&dev->kobjdevmajorminor);
|
||||
dev->kobjdevmajorminor.parent = NULL;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* devmajorminor_attr.h
|
||||
*
|
||||
* Copyright (C) 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
#ifndef __DEVMAJORMINOR_ATTR_H__
|
||||
#define __DEVMAJORMINOR_ATTR_H__
|
||||
|
||||
#include "visorbus.h" /* just to get visor_device declaration */
|
||||
#include "timskmod.h"
|
||||
|
||||
int register_devmajorminor_attributes(struct visor_device *dev);
|
||||
void unregister_devmajorminor_attributes(struct visor_device *dev);
|
||||
int devmajorminor_create_file(struct visor_device *dev, const char *nam,
|
||||
int major, int minor);
|
||||
void devmajorminor_remove_file(struct visor_device *dev, int slot);
|
||||
void devmajorminor_remove_all_files(struct visor_device *dev);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,166 @@
|
|||
/* visorbus.h
|
||||
*
|
||||
* Copyright (C) 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This header file is to be included by other kernel mode components that
|
||||
* implement a particular kind of visor_device. Each of these other kernel
|
||||
* mode components is called a visor device driver. Refer to visortemplate
|
||||
* for a minimal sample visor device driver.
|
||||
*
|
||||
* There should be nothing in this file that is private to the visorbus
|
||||
* bus implementation itself.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VISORBUS_H__
|
||||
#define __VISORBUS_H__
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/uuid.h>
|
||||
|
||||
#include "periodic_work.h"
|
||||
#include "visorchannel.h"
|
||||
#include "channel.h"
|
||||
|
||||
struct visor_driver;
|
||||
struct visor_device;
|
||||
|
||||
typedef void (*visorbus_state_complete_func) (struct visor_device *dev,
|
||||
int status);
|
||||
|
||||
/** This struct describes a specific Supervisor channel, by providing its
|
||||
* GUID, name, and sizes.
|
||||
*/
|
||||
struct visor_channeltype_descriptor {
|
||||
const uuid_le guid;
|
||||
const char *name;
|
||||
unsigned long min_size;
|
||||
unsigned long max_size;
|
||||
};
|
||||
|
||||
/** Information provided by each visor driver when it registers with the
|
||||
* visorbus driver.
|
||||
*/
|
||||
struct visor_driver {
|
||||
const char *name;
|
||||
const char *version;
|
||||
const char *vertag;
|
||||
const char *build_date;
|
||||
const char *build_time;
|
||||
struct module *owner;
|
||||
|
||||
/** Types of channels handled by this driver, ending with 0 GUID.
|
||||
* Our specialized BUS.match() method knows about this list, and
|
||||
* uses it to determine whether this driver will in fact handle a
|
||||
* new device that it has detected.
|
||||
*/
|
||||
struct visor_channeltype_descriptor *channel_types;
|
||||
|
||||
/** Called when a new device comes online, by our probe() function
|
||||
* specified by driver.probe() (triggered ultimately by some call
|
||||
* to driver_register() / bus_add_driver() / driver_attach()).
|
||||
*/
|
||||
int (*probe)(struct visor_device *dev);
|
||||
|
||||
/** Called when a new device is removed, by our remove() function
|
||||
* specified by driver.remove() (triggered ultimately by some call
|
||||
* to device_release_driver()).
|
||||
*/
|
||||
void (*remove)(struct visor_device *dev);
|
||||
|
||||
/** Called periodically, whenever there is a possibility that
|
||||
* "something interesting" may have happened to the channel state.
|
||||
*/
|
||||
void (*channel_interrupt)(struct visor_device *dev);
|
||||
|
||||
/** Called to initiate a change of the device's state. If the return
|
||||
* valu`e is < 0, there was an error and the state transition will NOT
|
||||
* occur. If the return value is >= 0, then the state transition was
|
||||
* INITIATED successfully, and complete_func() will be called (or was
|
||||
* just called) with the final status when either the state transition
|
||||
* fails or completes successfully.
|
||||
*/
|
||||
int (*pause)(struct visor_device *dev,
|
||||
visorbus_state_complete_func complete_func);
|
||||
int (*resume)(struct visor_device *dev,
|
||||
visorbus_state_complete_func complete_func);
|
||||
|
||||
/** These fields are for private use by the bus driver only. */
|
||||
struct device_driver driver;
|
||||
struct driver_attribute version_attr;
|
||||
};
|
||||
|
||||
#define to_visor_driver(x) container_of(x, struct visor_driver, driver)
|
||||
|
||||
/** A device type for things "plugged" into the visorbus bus */
|
||||
|
||||
struct visor_device {
|
||||
/** visor driver can use the visorchannel member with the functions
|
||||
* defined in visorchannel.h to access the channel
|
||||
*/
|
||||
struct visorchannel *visorchannel;
|
||||
uuid_le channel_type_guid;
|
||||
u64 channel_bytes;
|
||||
|
||||
/** These fields are for private use by the bus driver only.
|
||||
* A notable exception is that the visor driver can use
|
||||
* visor_get_drvdata() and visor_set_drvdata() to retrieve or stash
|
||||
* private visor driver specific data within the device member.
|
||||
*/
|
||||
struct device device;
|
||||
struct list_head list_all;
|
||||
struct periodic_work *periodic_work;
|
||||
bool being_removed;
|
||||
bool responded_to_device_create;
|
||||
struct kobject kobjchannel; /* visorbus<x>/dev<y>/channel/ */
|
||||
struct kobject kobjdevmajorminor; /* visorbus<x>/dev<y>/devmajorminor/*/
|
||||
struct {
|
||||
int major, minor;
|
||||
void *attr; /* private use by devmajorminor_attr.c you can
|
||||
* change this constant to whatever you
|
||||
* want; */
|
||||
} devnodes[5];
|
||||
/* the code will detect and behave appropriately) */
|
||||
struct semaphore visordriver_callback_lock;
|
||||
bool pausing;
|
||||
bool resuming;
|
||||
unsigned long chipset_bus_no;
|
||||
unsigned long chipset_dev_no;
|
||||
};
|
||||
|
||||
#define to_visor_device(x) container_of(x, struct visor_device, device)
|
||||
|
||||
#ifndef STANDALONE_CLIENT
|
||||
int visorbus_register_visor_driver(struct visor_driver *);
|
||||
void visorbus_unregister_visor_driver(struct visor_driver *);
|
||||
int visorbus_read_channel(struct visor_device *dev,
|
||||
unsigned long offset, void *dest,
|
||||
unsigned long nbytes);
|
||||
int visorbus_write_channel(struct visor_device *dev,
|
||||
unsigned long offset, void *src,
|
||||
unsigned long nbytes);
|
||||
int visorbus_clear_channel(struct visor_device *dev,
|
||||
unsigned long offset, u8 ch, unsigned long nbytes);
|
||||
int visorbus_registerdevnode(struct visor_device *dev,
|
||||
const char *name, int major, int minor);
|
||||
void visorbus_enable_channel_interrupts(struct visor_device *dev);
|
||||
void visorbus_disable_channel_interrupts(struct visor_device *dev);
|
||||
#endif
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,50 @@
|
|||
/* visorbus_private.h
|
||||
*
|
||||
* Copyright (C) 2010 - 2013 UNISYS CORPORATION
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*/
|
||||
|
||||
#ifndef __VISORBUS_PRIVATE_H__
|
||||
#define __VISORBUS_PRIVATE_H__
|
||||
|
||||
#include "timskmod.h"
|
||||
#include "visorbus.h"
|
||||
#include "visorchipset.h"
|
||||
#include "visorchannel.h"
|
||||
#include "version.h"
|
||||
#include "vbuschannel.h"
|
||||
|
||||
/* module parameters */
|
||||
extern int visorbus_debug;
|
||||
extern int visorbus_forcematch;
|
||||
extern int visorbus_forcenomatch;
|
||||
#define MAXDEVICETEST 4
|
||||
extern int visorbus_devicetest;
|
||||
extern int visorbus_debugref;
|
||||
extern int visorbus_serialloopbacktest;
|
||||
#define SERIALLOOPBACKCHANADDR (100 * 1024 * 1024)
|
||||
|
||||
/** This is the private data that we store for each bus device instance.
|
||||
*/
|
||||
struct visorbus_devdata {
|
||||
int devno; /* this is the chipset busNo */
|
||||
struct list_head list_all;
|
||||
struct device *dev;
|
||||
struct kobject kobj;
|
||||
struct visorchannel *chan; /* channel area for bus itself */
|
||||
bool vbus_valid;
|
||||
struct spar_vbus_headerinfo vbus_hdr_info;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue