]> rtime.felk.cvut.cz Git - socketcan-devel.git/blob - kernel/2.6/drivers/net/can/softing/softing_sysfs.c
Added channel information in sysfs.
[socketcan-devel.git] / kernel / 2.6 / drivers / net / can / softing / softing_sysfs.c
1 /*
2 * drivers/net/can/softing/softing_sysfs.c
3 *
4 * Copyright (C) 2009
5 *
6 * - Kurt Van Dijck, EIA Electronics
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the version 2 of the GNU General Public License
10 * as published by the Free Software Foundation
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include <linux/version.h>
23 #include <linux/module.h>
24 #include <linux/device.h>
25 #include <linux/mutex.h>
26
27 #include "softing.h"
28
29 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
30 #error This driver does not support Kernel versions < 2.6.23
31 #endif
32
33 /*sysfs stuff*/
34
35 /* Because the struct softing may be used by pcmcia devices
36  * as well as pci devices, * we have no clue how to get
37  * from a struct device * towards the struct softing *.
38  * It may go over a pci_device->priv or over a pcmcia_device->priv.
39  * Therefore, provide the struct softing pointer within the attribute.
40  * Then we don't need driver/bus specific things in these attributes
41  */
42 struct softing_attribute {
43         struct device_attribute dev;
44         ssize_t (*show) (struct softing *card, char *buf);
45         ssize_t (*store)(struct softing *card, const char *buf, size_t count);
46         struct softing *card;
47 };
48
49 static ssize_t rd_card_attr(struct device *dev, struct device_attribute *attr
50                 , char *buf) {
51         struct softing_attribute *cattr
52                 = container_of(attr, struct softing_attribute, dev);
53         return cattr->show ? cattr->show(cattr->card, buf) : 0;
54 }
55 static ssize_t wr_card_attr(struct device *dev, struct device_attribute *attr
56                 , const char *buf, size_t count) {
57         struct softing_attribute *cattr
58                 = container_of(attr, struct softing_attribute, dev);
59         return cattr->store ? cattr->store(cattr->card, buf, count) : 0;
60 }
61
62 #define declare_attr(_name, _mode, _show, _store) { \
63         .dev = { \
64                 .attr = { \
65                         .name = __stringify(_name), \
66                         .mode = _mode, \
67                 }, \
68                 .show = rd_card_attr, \
69                 .store = wr_card_attr, \
70         }, \
71         .show = _show, \
72         .store = _store, \
73 }
74
75 #define CARD_SHOW(name, member) \
76 static ssize_t show_##name(struct softing *card, char *buf) { \
77         return sprintf(buf, "%u\n", card->member); \
78 }
79 CARD_SHOW(serial        , id.serial);
80 CARD_SHOW(firmware      , id.fw);
81 CARD_SHOW(hardware      , id.hw);
82 CARD_SHOW(license       , id.lic);
83 CARD_SHOW(freq          , id.freq);
84 CARD_SHOW(txpending     , tx.pending);
85
86 static const struct softing_attribute card_attr_proto[] = {
87         declare_attr(serial     , 0444, show_serial     , 0),
88         declare_attr(firmware   , 0444, show_firmware   , 0),
89         declare_attr(hardware   , 0444, show_hardware   , 0),
90         declare_attr(license    , 0444, show_license    , 0),
91         declare_attr(freq       , 0444, show_freq       , 0),
92         declare_attr(txpending  , 0644, show_txpending  , 0),
93 };
94
95 int softing_card_sysfs_create(struct softing *card)
96 {
97         int size;
98         int j;
99
100         size = sizeof(card_attr_proto)/sizeof(card_attr_proto[0]);
101         card->attr = kmalloc((size+1)*sizeof(card->attr[0]), GFP_KERNEL);
102         if (!card->attr)
103                 goto attr_mem_failed;
104         memcpy(card->attr, card_attr_proto, size * sizeof(card->attr[0]));
105         memset(&card->attr[size], 0, sizeof(card->attr[0]));
106
107         card->grp  = kmalloc((size+1)*sizeof(card->grp[0]), GFP_KERNEL);
108         if (!card->grp)
109                 goto grp_mem_failed;
110
111         for (j = 0; j < size; ++j) {
112                 card->attr[j].card = card;
113                 card->grp[j] = &card->attr[j].dev.attr;
114                 if (!card->attr[j].show)
115                         card->attr[j].dev.attr.mode &= ~(S_IRUGO);
116                 if (!card->attr[j].store)
117                         card->attr[j].dev.attr.mode &= ~(S_IWUGO);
118         }
119         card->grp[size] = 0;
120         card->sysfs.name        = "softing";
121         card->sysfs.attrs = card->grp;
122         if (sysfs_create_group(&card->dev->kobj, &card->sysfs) < 0)
123                 goto sysfs_failed;
124
125         return 0;
126
127 sysfs_failed:
128         kfree(card->grp);
129 grp_mem_failed:
130         kfree(card->attr);
131 attr_mem_failed:
132         return -1;
133 }
134 void softing_card_sysfs_remove(struct softing *card)
135 {
136         sysfs_remove_group(&card->dev->kobj, &card->sysfs);
137         kfree(card->grp);
138         kfree(card->attr);
139 }
140
141 static ssize_t show_channel(struct device *dev
142                 , struct device_attribute *attr, char *buf)
143 {
144         struct net_device *ndev = to_net_dev(dev);
145         struct softing_priv *priv = netdev2softing(ndev);
146         return sprintf(buf, "%i\n", priv->index);
147 }
148
149 static ssize_t show_chip(struct device *dev
150                 , struct device_attribute *attr, char *buf)
151 {
152         struct net_device *ndev = to_net_dev(dev);
153         struct softing_priv *priv = netdev2softing(ndev);
154         return sprintf(buf, "%i\n", priv->chip);
155 }
156
157 static ssize_t show_output(struct device *dev
158                 , struct device_attribute *attr, char *buf)
159 {
160         struct net_device *ndev = to_net_dev(dev);
161         struct softing_priv *priv = netdev2softing(ndev);
162         return sprintf(buf, "0x%02x\n", priv->output);
163 }
164
165 static ssize_t store_output(struct device *dev
166                 , struct device_attribute *attr
167                 , const char *buf, size_t count)
168 {
169         struct net_device *ndev = to_net_dev(dev);
170         struct softing_priv *priv = netdev2softing(ndev);
171         struct softing *card = priv->card;
172         unsigned long val;
173         int ret;
174
175         ret = strict_strtoul(buf, 0, &val);
176         if (ret < 0)
177                 return ret;
178         val &= 0xFF;
179
180         ret = mutex_lock_interruptible(&card->fw.lock);
181         if (ret)
182                 return -ERESTARTSYS;
183         if (netif_running(ndev)) {
184                 mutex_unlock(&card->fw.lock);
185                 return -EBUSY;
186         }
187         priv->output = val;
188         mutex_unlock(&card->fw.lock);
189         return count;
190 }
191 /* TODO
192  * the latest softing cards support sleep mode too
193  */
194
195 static const DEVICE_ATTR(channel, S_IRUGO, show_channel, 0);
196 static const DEVICE_ATTR(chip, S_IRUGO, show_chip, 0);
197 static const DEVICE_ATTR(output, S_IRUGO | S_IWUSR, show_output, store_output);
198
199 static const struct attribute *const netdev_sysfs_entries[] = {
200         &dev_attr_channel       .attr,
201         &dev_attr_chip          .attr,
202         &dev_attr_output        .attr,
203         0,
204 };
205 static const struct attribute_group netdev_sysfs = {
206         .name  = 0,
207         .attrs = (struct attribute **)netdev_sysfs_entries,
208 };
209
210 int softing_bus_sysfs_create(struct softing_priv *priv)
211 {
212         if (!priv->netdev->dev.kobj.sd) {
213                 dev_alert(priv->card->dev, "sysfs_create_group would fail\n");
214                 return ENODEV;
215         }
216         return sysfs_create_group(&priv->netdev->dev.kobj, &netdev_sysfs);
217 }
218 void softing_bus_sysfs_remove(struct softing_priv *priv)
219 {
220         sysfs_remove_group(&priv->netdev->dev.kobj, &netdev_sysfs);
221 }
222