linux/drivers/rapidio/rio-sysfs.c
<<
>>
Prefs
   1/*
   2 * RapidIO sysfs attributes and support
   3 *
   4 * Copyright 2005 MontaVista Software, Inc.
   5 * Matt Porter <mporter@kernel.crashing.org>
   6 *
   7 * This program is free software; you can redistribute  it and/or modify it
   8 * under  the terms of  the GNU General  Public License as published by the
   9 * Free Software Foundation;  either version 2 of the  License, or (at your
  10 * option) any later version.
  11 */
  12
  13#include <linux/kernel.h>
  14#include <linux/rio.h>
  15#include <linux/rio_drv.h>
  16#include <linux/stat.h>
  17
  18#include "rio.h"
  19
  20/* Sysfs support */
  21#define rio_config_attr(field, format_string)                                   \
  22static ssize_t                                                          \
  23field##_show(struct device *dev, struct device_attribute *attr, char *buf)                      \
  24{                                                                       \
  25        struct rio_dev *rdev = to_rio_dev(dev);                         \
  26                                                                        \
  27        return sprintf(buf, format_string, rdev->field);                \
  28}                                                                       \
  29
  30rio_config_attr(did, "0x%04x\n");
  31rio_config_attr(vid, "0x%04x\n");
  32rio_config_attr(device_rev, "0x%08x\n");
  33rio_config_attr(asm_did, "0x%04x\n");
  34rio_config_attr(asm_vid, "0x%04x\n");
  35rio_config_attr(asm_rev, "0x%04x\n");
  36
  37static ssize_t routes_show(struct device *dev, struct device_attribute *attr, char *buf)
  38{
  39        struct rio_dev *rdev = to_rio_dev(dev);
  40        char *str = buf;
  41        int i;
  42
  43        if (!rdev->rswitch)
  44                goto out;
  45
  46        for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size);
  47                        i++) {
  48                if (rdev->rswitch->route_table[i] == RIO_INVALID_ROUTE)
  49                        continue;
  50                str +=
  51                    sprintf(str, "%04x %02x\n", i,
  52                            rdev->rswitch->route_table[i]);
  53        }
  54
  55      out:
  56        return (str - buf);
  57}
  58
  59struct device_attribute rio_dev_attrs[] = {
  60        __ATTR_RO(did),
  61        __ATTR_RO(vid),
  62        __ATTR_RO(device_rev),
  63        __ATTR_RO(asm_did),
  64        __ATTR_RO(asm_vid),
  65        __ATTR_RO(asm_rev),
  66        __ATTR_RO(routes),
  67        __ATTR_NULL,
  68};
  69
  70static ssize_t
  71rio_read_config(struct kobject *kobj, struct bin_attribute *bin_attr,
  72                char *buf, loff_t off, size_t count)
  73{
  74        struct rio_dev *dev =
  75            to_rio_dev(container_of(kobj, struct device, kobj));
  76        unsigned int size = 0x100;
  77        loff_t init_off = off;
  78        u8 *data = (u8 *) buf;
  79
  80        /* Several chips lock up trying to read undefined config space */
  81        if (capable(CAP_SYS_ADMIN))
  82                size = 0x200000;
  83
  84        if (off > size)
  85                return 0;
  86        if (off + count > size) {
  87                size -= off;
  88                count = size;
  89        } else {
  90                size = count;
  91        }
  92
  93        if ((off & 1) && size) {
  94                u8 val;
  95                rio_read_config_8(dev, off, &val);
  96                data[off - init_off] = val;
  97                off++;
  98                size--;
  99        }
 100
 101        if ((off & 3) && size > 2) {
 102                u16 val;
 103                rio_read_config_16(dev, off, &val);
 104                data[off - init_off] = (val >> 8) & 0xff;
 105                data[off - init_off + 1] = val & 0xff;
 106                off += 2;
 107                size -= 2;
 108        }
 109
 110        while (size > 3) {
 111                u32 val;
 112                rio_read_config_32(dev, off, &val);
 113                data[off - init_off] = (val >> 24) & 0xff;
 114                data[off - init_off + 1] = (val >> 16) & 0xff;
 115                data[off - init_off + 2] = (val >> 8) & 0xff;
 116                data[off - init_off + 3] = val & 0xff;
 117                off += 4;
 118                size -= 4;
 119        }
 120
 121        if (size >= 2) {
 122                u16 val;
 123                rio_read_config_16(dev, off, &val);
 124                data[off - init_off] = (val >> 8) & 0xff;
 125                data[off - init_off + 1] = val & 0xff;
 126                off += 2;
 127                size -= 2;
 128        }
 129
 130        if (size > 0) {
 131                u8 val;
 132                rio_read_config_8(dev, off, &val);
 133                data[off - init_off] = val;
 134                off++;
 135                --size;
 136        }
 137
 138        return count;
 139}
 140
 141static ssize_t
 142rio_write_config(struct kobject *kobj, struct bin_attribute *bin_attr,
 143                 char *buf, loff_t off, size_t count)
 144{
 145        struct rio_dev *dev =
 146            to_rio_dev(container_of(kobj, struct device, kobj));
 147        unsigned int size = count;
 148        loff_t init_off = off;
 149        u8 *data = (u8 *) buf;
 150
 151        if (off > 0x200000)
 152                return 0;
 153        if (off + count > 0x200000) {
 154                size = 0x200000 - off;
 155                count = size;
 156        }
 157
 158        if ((off & 1) && size) {
 159                rio_write_config_8(dev, off, data[off - init_off]);
 160                off++;
 161                size--;
 162        }
 163
 164        if ((off & 3) && (size > 2)) {
 165                u16 val = data[off - init_off + 1];
 166                val |= (u16) data[off - init_off] << 8;
 167                rio_write_config_16(dev, off, val);
 168                off += 2;
 169                size -= 2;
 170        }
 171
 172        while (size > 3) {
 173                u32 val = data[off - init_off + 3];
 174                val |= (u32) data[off - init_off + 2] << 8;
 175                val |= (u32) data[off - init_off + 1] << 16;
 176                val |= (u32) data[off - init_off] << 24;
 177                rio_write_config_32(dev, off, val);
 178                off += 4;
 179                size -= 4;
 180        }
 181
 182        if (size >= 2) {
 183                u16 val = data[off - init_off + 1];
 184                val |= (u16) data[off - init_off] << 8;
 185                rio_write_config_16(dev, off, val);
 186                off += 2;
 187                size -= 2;
 188        }
 189
 190        if (size) {
 191                rio_write_config_8(dev, off, data[off - init_off]);
 192                off++;
 193                --size;
 194        }
 195
 196        return count;
 197}
 198
 199static struct bin_attribute rio_config_attr = {
 200        .attr = {
 201                 .name = "config",
 202                 .mode = S_IRUGO | S_IWUSR,
 203                 },
 204        .size = 0x200000,
 205        .read = rio_read_config,
 206        .write = rio_write_config,
 207};
 208
 209/**
 210 * rio_create_sysfs_dev_files - create RIO specific sysfs files
 211 * @rdev: device whose entries should be created
 212 *
 213 * Create files when @rdev is added to sysfs.
 214 */
 215int rio_create_sysfs_dev_files(struct rio_dev *rdev)
 216{
 217        int err = 0;
 218
 219        err = sysfs_create_bin_file(&rdev->dev.kobj, &rio_config_attr);
 220
 221        return err;
 222}
 223
 224/**
 225 * rio_remove_sysfs_dev_files - cleanup RIO specific sysfs files
 226 * @rdev: device whose entries we should free
 227 *
 228 * Cleanup when @rdev is removed from sysfs.
 229 */
 230void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
 231{
 232        sysfs_remove_bin_file(&rdev->dev.kobj, &rio_config_attr);
 233}
 234