/alps/ipecamera

To get this branch, use:
bzr branch http://darksoft.org/webbzr/alps/ipecamera

« back to all changes in this revision

Viewing changes to driver/sysfs.c

  • Committer: Suren A. Chilingaryan
  • Date: 2015-04-27 00:28:57 UTC
  • Revision ID: csa@suren.me-20150427002857-82fk6r3e8rfgy4wr
First stand-alone ipecamera implementation

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 *
3
 
 * @file sysfs.c
4
 
 * @brief This file contains the functions providing the SysFS-interface.
5
 
 * @author Guillermo Marcus
6
 
 * @date 2010-03-01
7
 
 *
8
 
 */
9
 
#include <linux/version.h>
10
 
#include <linux/string.h>
11
 
#include <linux/types.h>
12
 
#include <linux/list.h>
13
 
#include <linux/interrupt.h>
14
 
#include <linux/pci.h>
15
 
#include <linux/cdev.h>
16
 
#include <linux/wait.h>
17
 
#include <linux/mm.h>
18
 
#include <linux/pagemap.h>
19
 
#include <linux/kernel.h>
20
 
 
21
 
#include "compat.h"
22
 
#include "config.h"
23
 
#include "pciDriver.h"
24
 
#include "common.h"
25
 
#include "umem.h"
26
 
#include "kmem.h"
27
 
#include "sysfs.h"
28
 
 
29
 
static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry);
30
 
static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry);
31
 
 
32
 
/**
33
 
 *
34
 
 * Initializes the sysfs attributes for an kmem/umem-entry
35
 
 *
36
 
 */
37
 
static int _pcidriver_sysfs_initialize(pcidriver_privdata_t *privdata,
38
 
                                        int id,
39
 
                                        struct class_device_attribute *sysfs_attr,
40
 
                                        const char *fmtstring,
41
 
                                        SYSFS_GET_FUNCTION((*callback)))
42
 
{
43
 
        /* sysfs attributes for kmem buffers don’t make sense before 2.6.13, as
44
 
           we have no mmap support before */
45
 
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
46
 
        char namebuffer[16];
47
 
 
48
 
        /* allocate space for the name of the attribute */
49
 
        snprintf(namebuffer, sizeof(namebuffer), fmtstring, id);
50
 
 
51
 
        if ((sysfs_attr->attr.name = kstrdup(namebuffer, GFP_KERNEL)) == NULL)
52
 
                return -ENOMEM;
53
 
 
54
 
        sysfs_attr->attr.mode = S_IRUGO;
55
 
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
56
 
            // DS: Shall we lock now while accessing driver data structures???
57
 
        sysfs_attr->attr.owner = THIS_MODULE;
58
 
#endif
59
 
        sysfs_attr->show = callback;
60
 
        sysfs_attr->store = NULL;
61
 
                        
62
 
        /* name and add attribute */
63
 
        if (class_device_create_file(privdata->class_dev, sysfs_attr) != 0)
64
 
                return -ENXIO; /* Device not configured. Not the really best choice, but hm. */
65
 
#endif
66
 
 
67
 
        return 0;
68
 
}
69
 
 
70
 
int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr)
71
 
{
72
 
        return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "kbuf%d", pcidriver_show_kmem_entry);
73
 
}
74
 
 
75
 
int pcidriver_sysfs_initialize_umem(pcidriver_privdata_t *privdata, int id, struct class_device_attribute *sysfs_attr)
76
 
{
77
 
        return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "umem%d", pcidriver_show_umem_entry);
78
 
}
79
 
 
80
 
/**
81
 
 *
82
 
 * Removes the file from sysfs and frees the allocated (kstrdup()) memory.
83
 
 *
84
 
 */
85
 
void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct class_device_attribute *sysfs_attr)
86
 
{
87
 
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
88
 
        class_device_remove_file(privdata->class_dev, sysfs_attr);
89
 
        kfree(sysfs_attr->attr.name);
90
 
#endif
91
 
}
92
 
 
93
 
static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry)
94
 
{
95
 
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
96
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
97
 
 
98
 
        /* As we can be sure that attr.name contains a filename which we
99
 
         * created (see _pcidriver_sysfs_initialize), we do not need to have
100
 
         * sanity checks but can directly call simple_strtol() */
101
 
        int id = simple_strtol(attr->attr.name + strlen("kbuf"), NULL, 10);
102
 
        pcidriver_kmem_entry_t *entry = pcidriver_kmem_find_entry_id(privdata, id);
103
 
        if (entry) {
104
 
            unsigned long addr = entry->cpua;
105
 
            unsigned long dma_addr = entry->dma_handle;
106
 
            
107
 
            if (entry->size >= 16) {
108
 
                pcidriver_kmem_sync_entry(privdata, entry, PCILIB_KMEM_SYNC_FROMDEVICE);
109
 
                return snprintf(buf, PAGE_SIZE, "buffer: %d\naddr: %lx\nhw addr: %llx\nbus addr: %lx\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\ndata: %8x %8x %8x %8x\n", id, addr, virt_to_phys((void*)addr), dma_addr, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode, *(u32*)(entry->cpua), *(u32*)(entry->cpua + 4),  *(u32*)(entry->cpua + 8), *(u32*)(entry->cpua + 12));
110
 
            } else
111
 
                return snprintf(buf, PAGE_SIZE, "buffer: %d\naddr: %lx\nhw addr: %llx\nbus addr: %lx\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\n", id, addr, virt_to_phys((void*)addr), dma_addr, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode);
112
 
        } else
113
 
            return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id);
114
 
#else
115
 
        return 0;
116
 
#endif
117
 
}
118
 
 
119
 
static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry)
120
 
{
121
 
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13)
122
 
#if 0
123
 
        pcidriver_privdata_t *privdata = (pcidriver_privdata_t *)cls->class_data;
124
 
 
125
 
        return snprintf(buf, PAGE_SIZE, "I am in the umem_entry show function, class_device_kobj_name: %s\n", cls->kobj.name);
126
 
#endif
127
 
        return 0;
128
 
#else
129
 
        return 0;
130
 
#endif
131
 
}
132
 
 
133
 
#ifdef ENABLE_IRQ
134
 
SYSFS_GET_FUNCTION(pcidriver_show_irq_count)
135
 
{
136
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
137
 
 
138
 
        return snprintf(buf, PAGE_SIZE, "%d\n", privdata->irq_count);
139
 
}
140
 
 
141
 
SYSFS_GET_FUNCTION(pcidriver_show_irq_queues)
142
 
{
143
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
144
 
        int i, offset;
145
 
 
146
 
        /* output will be truncated to PAGE_SIZE */
147
 
        offset = snprintf(buf, PAGE_SIZE, "Queue\tOutstanding IRQs\n");
148
 
        for (i = 0; i < PCIDRIVER_INT_MAXSOURCES; i++)
149
 
                offset += snprintf(buf+offset, PAGE_SIZE-offset, "%d\t%d\n", i, atomic_read(&(privdata->irq_outstanding[i])) );
150
 
 
151
 
        return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
152
 
}
153
 
#endif
154
 
 
155
 
SYSFS_GET_FUNCTION(pcidriver_show_mmap_mode)
156
 
{
157
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
158
 
 
159
 
        return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_mode);
160
 
}
161
 
 
162
 
SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode)
163
 
{
164
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
165
 
        int mode = -1;
166
 
 
167
 
        /* Set the mmap-mode if it is either PCIDRIVER_MMAP_PCI or PCIDRIVER_MMAP_KMEM */
168
 
        if (sscanf(buf, "%d", &mode) == 1 &&
169
 
            (mode == PCIDRIVER_MMAP_PCI || mode == PCIDRIVER_MMAP_KMEM))
170
 
                privdata->mmap_mode = mode;
171
 
 
172
 
        return strlen(buf);
173
 
}
174
 
 
175
 
SYSFS_GET_FUNCTION(pcidriver_show_mmap_area)
176
 
{
177
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
178
 
 
179
 
        return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_area);
180
 
}
181
 
 
182
 
SYSFS_SET_FUNCTION(pcidriver_store_mmap_area)
183
 
{
184
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
185
 
        int temp = -1;
186
 
 
187
 
        sscanf(buf, "%d", &temp);
188
 
 
189
 
        if ((temp >= PCIDRIVER_BAR0) && (temp <= PCIDRIVER_BAR5))
190
 
                privdata->mmap_area = temp;
191
 
 
192
 
        return strlen(buf);
193
 
}
194
 
 
195
 
SYSFS_GET_FUNCTION(pcidriver_show_kmem_count)
196
 
{
197
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
198
 
 
199
 
        return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&(privdata->kmem_count)));
200
 
}
201
 
 
202
 
SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc)
203
 
{
204
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
205
 
        kmem_handle_t kmem_handle;
206
 
 
207
 
        /* FIXME: guillermo: is validation of parsing an unsigned int enough? */
208
 
        if (sscanf(buf, "%lu", &kmem_handle.size) == 1)
209
 
                pcidriver_kmem_alloc(privdata, &kmem_handle);
210
 
 
211
 
        return strlen(buf);
212
 
}
213
 
 
214
 
SYSFS_SET_FUNCTION(pcidriver_store_kmem_free)
215
 
{
216
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
217
 
        unsigned int id;
218
 
        pcidriver_kmem_entry_t *kmem_entry;
219
 
 
220
 
        /* Parse the ID of the kernel memory to be freed, check bounds */
221
 
        if (sscanf(buf, "%u", &id) != 1 ||
222
 
            (id >= atomic_read(&(privdata->kmem_count))))
223
 
                goto err;
224
 
 
225
 
        if ((kmem_entry = pcidriver_kmem_find_entry_id(privdata,id)) == NULL)
226
 
                goto err;
227
 
 
228
 
        pcidriver_kmem_free_entry(privdata, kmem_entry );
229
 
err:
230
 
        return strlen(buf);
231
 
}
232
 
 
233
 
SYSFS_GET_FUNCTION(pcidriver_show_kbuffers)
234
 
{
235
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
236
 
        int offset = 0;
237
 
        struct list_head *ptr;
238
 
        pcidriver_kmem_entry_t *entry;
239
 
 
240
 
        /* print the header */
241
 
        offset += snprintf(buf, PAGE_SIZE, "kbuf#\tcpu addr\tsize\n");
242
 
 
243
 
        spin_lock(&(privdata->kmemlist_lock));
244
 
        list_for_each(ptr, &(privdata->kmem_list)) {
245
 
                entry = list_entry(ptr, pcidriver_kmem_entry_t, list);
246
 
 
247
 
                /* print entry info */
248
 
                if (offset > PAGE_SIZE) {
249
 
                        spin_unlock( &(privdata->kmemlist_lock) );
250
 
                        return PAGE_SIZE;
251
 
                }
252
 
 
253
 
                offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%08lx\t%lu\n", entry->id, (unsigned long)(entry->dma_handle), entry->size );
254
 
        }
255
 
 
256
 
        spin_unlock(&(privdata->kmemlist_lock));
257
 
 
258
 
        /* output will be truncated to PAGE_SIZE */
259
 
        return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
260
 
}
261
 
 
262
 
SYSFS_GET_FUNCTION(pcidriver_show_umappings)
263
 
{
264
 
        int offset = 0;
265
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
266
 
        struct list_head *ptr;
267
 
        pcidriver_umem_entry_t *entry;
268
 
 
269
 
        /* print the header */
270
 
        offset += snprintf(buf, PAGE_SIZE, "umap#\tn_pages\tsg_ents\n");
271
 
 
272
 
        spin_lock( &(privdata->umemlist_lock) );
273
 
        list_for_each( ptr, &(privdata->umem_list) ) {
274
 
                entry = list_entry(ptr, pcidriver_umem_entry_t, list );
275
 
 
276
 
                /* print entry info */
277
 
                if (offset > PAGE_SIZE) {
278
 
                        spin_unlock( &(privdata->umemlist_lock) );
279
 
                        return PAGE_SIZE;
280
 
                }
281
 
 
282
 
                offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%lu\t%lu\n", entry->id,
283
 
                                (unsigned long)(entry->nr_pages), (unsigned long)(entry->nents));
284
 
        }
285
 
 
286
 
        spin_unlock( &(privdata->umemlist_lock) );
287
 
 
288
 
        /* output will be truncated to PAGE_SIZE */
289
 
        return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1);
290
 
}
291
 
 
292
 
SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap)
293
 
{
294
 
        pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA;
295
 
        pcidriver_umem_entry_t *umem_entry;
296
 
        unsigned int id;
297
 
 
298
 
        if (sscanf(buf, "%u", &id) != 1 ||
299
 
            (id >= atomic_read(&(privdata->umem_count))))
300
 
                goto err;
301
 
 
302
 
        if ((umem_entry = pcidriver_umem_find_entry_id(privdata, id)) == NULL)
303
 
                goto err;
304
 
 
305
 
        pcidriver_umem_sgunmap(privdata, umem_entry);
306
 
err:
307
 
        return strlen(buf);
308
 
}