bzr branch
http://suren.me/webbzr/alps/pcitool
1
by Suren A. Chilingaryan
Initial import |
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 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
21 |
#include "base.h" |
22 |
||
23 |
#define SYSFS_GET_PRIVDATA dev_get_drvdata(dev)
|
|
24 |
#define SYSFS_GET_FUNCTION(name) ssize_t name(struct device *dev, struct device_attribute *attr, char *buf)
|
|
25 |
#define SYSFS_SET_FUNCTION(name) ssize_t name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
|
26 |
||
27 |
#define SYSFS_ATTR_NAME(name) (dev_attr_##name)
|
|
28 |
||
29 |
#define SYSFS_ATTR_CREATE(name) do { \
|
|
30 |
int err = device_create_file(privdata->class_dev, &SYSFS_ATTR_NAME(name)); \
|
|
31 |
if (err != 0) return err; \
|
|
32 |
} while (0)
|
|
33 |
||
34 |
#define SYSFS_ATTR_REMOVE(name) do { \
|
|
35 |
device_remove_file(privdata->class_dev, &SYSFS_ATTR_NAME(name)); \
|
|
36 |
} while (0)
|
|
1
by Suren A. Chilingaryan
Initial import |
37 |
|
38 |
#ifdef ENABLE_IRQ
|
|
365
by Suren A. Chilingaryan
Restructure driver headers |
39 |
static SYSFS_GET_FUNCTION(pcidriver_show_irq_count) |
1
by Suren A. Chilingaryan
Initial import |
40 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
41 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
1
by Suren A. Chilingaryan
Initial import |
42 |
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
43 |
return snprintf(buf, PAGE_SIZE, "%d\n", privdata->irq_count); |
1
by Suren A. Chilingaryan
Initial import |
44 |
}
|
45 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
46 |
static SYSFS_GET_FUNCTION(pcidriver_show_irq_queues) |
1
by Suren A. Chilingaryan
Initial import |
47 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
48 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
49 |
int i, offset; |
|
50 |
||
51 |
/* output will be truncated to PAGE_SIZE */
|
|
52 |
offset = snprintf(buf, PAGE_SIZE, "Queue\tOutstanding IRQs\n"); |
|
53 |
for (i = 0; i < PCIDRIVER_INT_MAXSOURCES; i++) |
|
54 |
offset += snprintf(buf+offset, PAGE_SIZE-offset, "%d\t%d\n", i, atomic_read(&(privdata->irq_outstanding[i])) ); |
|
55 |
||
56 |
return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1); |
|
1
by Suren A. Chilingaryan
Initial import |
57 |
}
|
58 |
#endif
|
|
59 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
60 |
static SYSFS_GET_FUNCTION(pcidriver_show_mmap_mode) |
1
by Suren A. Chilingaryan
Initial import |
61 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
62 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
1
by Suren A. Chilingaryan
Initial import |
63 |
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
64 |
return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_mode); |
1
by Suren A. Chilingaryan
Initial import |
65 |
}
|
66 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
67 |
static SYSFS_SET_FUNCTION(pcidriver_store_mmap_mode) |
1
by Suren A. Chilingaryan
Initial import |
68 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
69 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
70 |
int mode = -1; |
|
71 |
||
72 |
/* Set the mmap-mode if it is either PCIDRIVER_MMAP_PCI or PCIDRIVER_MMAP_KMEM */
|
|
73 |
if (sscanf(buf, "%d", &mode) == 1 && |
|
74 |
(mode == PCIDRIVER_MMAP_PCI || mode == PCIDRIVER_MMAP_KMEM)) |
|
75 |
privdata->mmap_mode = mode; |
|
76 |
||
77 |
return strlen(buf); |
|
1
by Suren A. Chilingaryan
Initial import |
78 |
}
|
79 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
80 |
static SYSFS_GET_FUNCTION(pcidriver_show_mmap_area) |
1
by Suren A. Chilingaryan
Initial import |
81 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
82 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
1
by Suren A. Chilingaryan
Initial import |
83 |
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
84 |
return snprintf(buf, PAGE_SIZE, "%d\n", privdata->mmap_area); |
1
by Suren A. Chilingaryan
Initial import |
85 |
}
|
86 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
87 |
static SYSFS_SET_FUNCTION(pcidriver_store_mmap_area) |
1
by Suren A. Chilingaryan
Initial import |
88 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
89 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
90 |
int temp = -1; |
|
91 |
||
92 |
sscanf(buf, "%d", &temp); |
|
93 |
||
94 |
if ((temp >= PCIDRIVER_BAR0) && (temp <= PCIDRIVER_BAR5)) |
|
95 |
privdata->mmap_area = temp; |
|
96 |
||
97 |
return strlen(buf); |
|
1
by Suren A. Chilingaryan
Initial import |
98 |
}
|
99 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
100 |
static SYSFS_GET_FUNCTION(pcidriver_show_kmem_count) |
1
by Suren A. Chilingaryan
Initial import |
101 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
102 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
1
by Suren A. Chilingaryan
Initial import |
103 |
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
104 |
return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&(privdata->kmem_count))); |
1
by Suren A. Chilingaryan
Initial import |
105 |
}
|
106 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
107 |
static SYSFS_SET_FUNCTION(pcidriver_store_kmem_alloc) |
1
by Suren A. Chilingaryan
Initial import |
108 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
109 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
110 |
kmem_handle_t kmem_handle; |
|
111 |
||
112 |
/* FIXME: guillermo: is validation of parsing an unsigned int enough? */
|
|
113 |
if (sscanf(buf, "%lu", &kmem_handle.size) == 1) |
|
114 |
pcidriver_kmem_alloc(privdata, &kmem_handle); |
|
115 |
||
116 |
return strlen(buf); |
|
1
by Suren A. Chilingaryan
Initial import |
117 |
}
|
118 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
119 |
static SYSFS_SET_FUNCTION(pcidriver_store_kmem_free) |
1
by Suren A. Chilingaryan
Initial import |
120 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
121 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
122 |
unsigned int id; |
|
123 |
pcidriver_kmem_entry_t *kmem_entry; |
|
124 |
||
125 |
/* Parse the ID of the kernel memory to be freed, check bounds */
|
|
126 |
if (sscanf(buf, "%u", &id) != 1 || |
|
127 |
(id >= atomic_read(&(privdata->kmem_count)))) |
|
128 |
goto err; |
|
129 |
||
130 |
if ((kmem_entry = pcidriver_kmem_find_entry_id(privdata,id)) == NULL) |
|
131 |
goto err; |
|
132 |
||
133 |
pcidriver_kmem_free_entry(privdata, kmem_entry ); |
|
1
by Suren A. Chilingaryan
Initial import |
134 |
err: |
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
135 |
return strlen(buf); |
1
by Suren A. Chilingaryan
Initial import |
136 |
}
|
137 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
138 |
static SYSFS_GET_FUNCTION(pcidriver_show_kbuffers) |
1
by Suren A. Chilingaryan
Initial import |
139 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
140 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
141 |
int offset = 0; |
|
142 |
struct list_head *ptr; |
|
143 |
pcidriver_kmem_entry_t *entry; |
|
144 |
||
145 |
/* print the header */
|
|
146 |
offset += snprintf(buf, PAGE_SIZE, "kbuf#\tcpu addr\tsize\n"); |
|
147 |
||
148 |
spin_lock(&(privdata->kmemlist_lock)); |
|
149 |
list_for_each(ptr, &(privdata->kmem_list)) { |
|
150 |
entry = list_entry(ptr, pcidriver_kmem_entry_t, list); |
|
151 |
||
152 |
/* print entry info */
|
|
153 |
if (offset > PAGE_SIZE) { |
|
154 |
spin_unlock( &(privdata->kmemlist_lock) ); |
|
155 |
return PAGE_SIZE; |
|
156 |
}
|
|
157 |
||
158 |
offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%08lx\t%lu\n", entry->id, (unsigned long)(entry->dma_handle), entry->size ); |
|
159 |
}
|
|
160 |
||
161 |
spin_unlock(&(privdata->kmemlist_lock)); |
|
162 |
||
163 |
/* output will be truncated to PAGE_SIZE */
|
|
164 |
return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1); |
|
1
by Suren A. Chilingaryan
Initial import |
165 |
}
|
166 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
167 |
static SYSFS_GET_FUNCTION(pcidriver_show_umappings) |
1
by Suren A. Chilingaryan
Initial import |
168 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
169 |
int offset = 0; |
170 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
|
171 |
struct list_head *ptr; |
|
172 |
pcidriver_umem_entry_t *entry; |
|
173 |
||
174 |
/* print the header */
|
|
175 |
offset += snprintf(buf, PAGE_SIZE, "umap#\tn_pages\tsg_ents\n"); |
|
176 |
||
177 |
spin_lock( &(privdata->umemlist_lock) ); |
|
178 |
list_for_each( ptr, &(privdata->umem_list) ) { |
|
179 |
entry = list_entry(ptr, pcidriver_umem_entry_t, list ); |
|
180 |
||
181 |
/* print entry info */
|
|
182 |
if (offset > PAGE_SIZE) { |
|
183 |
spin_unlock( &(privdata->umemlist_lock) ); |
|
184 |
return PAGE_SIZE; |
|
185 |
}
|
|
186 |
||
187 |
offset += snprintf(buf+offset, PAGE_SIZE-offset, "%3d\t%lu\t%lu\n", entry->id, |
|
188 |
(unsigned long)(entry->nr_pages), (unsigned long)(entry->nents)); |
|
189 |
}
|
|
190 |
||
191 |
spin_unlock( &(privdata->umemlist_lock) ); |
|
192 |
||
193 |
/* output will be truncated to PAGE_SIZE */
|
|
194 |
return (offset > PAGE_SIZE ? PAGE_SIZE : offset+1); |
|
1
by Suren A. Chilingaryan
Initial import |
195 |
}
|
196 |
||
365
by Suren A. Chilingaryan
Restructure driver headers |
197 |
static SYSFS_SET_FUNCTION(pcidriver_store_umem_unmap) |
1
by Suren A. Chilingaryan
Initial import |
198 |
{
|
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
199 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
200 |
pcidriver_umem_entry_t *umem_entry; |
|
201 |
unsigned int id; |
|
202 |
||
203 |
if (sscanf(buf, "%u", &id) != 1 || |
|
204 |
(id >= atomic_read(&(privdata->umem_count)))) |
|
205 |
goto err; |
|
206 |
||
207 |
if ((umem_entry = pcidriver_umem_find_entry_id(privdata, id)) == NULL) |
|
208 |
goto err; |
|
209 |
||
210 |
pcidriver_umem_sgunmap(privdata, umem_entry); |
|
1
by Suren A. Chilingaryan
Initial import |
211 |
err: |
364
by Suren A. Chilingaryan
Drop support of kernels prior to 3.2 (Debian 7, Ubuntu 12.04) |
212 |
return strlen(buf); |
1
by Suren A. Chilingaryan
Initial import |
213 |
}
|
365
by Suren A. Chilingaryan
Restructure driver headers |
214 |
|
215 |
static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry) |
|
216 |
{
|
|
217 |
pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; |
|
218 |
||
219 |
/* As we can be sure that attr.name contains a filename which we
|
|
220 |
* created (see _pcidriver_sysfs_initialize), we do not need to have
|
|
221 |
* sanity checks but can directly call simple_strtol() */
|
|
222 |
int id = simple_strtol(attr->attr.name + strlen("kbuf"), NULL, 10); |
|
223 |
pcidriver_kmem_entry_t *entry = pcidriver_kmem_find_entry_id(privdata, id); |
|
224 |
if (entry) { |
|
225 |
unsigned long addr = entry->cpua; |
|
226 |
unsigned long dma_addr = entry->dma_handle; |
|
227 |
||
228 |
if (entry->size >= 16) { |
|
229 |
pcidriver_kmem_sync_entry(privdata, entry, PCILIB_KMEM_SYNC_FROMDEVICE); |
|
230 |
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)); |
|
231 |
} else |
|
232 |
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); |
|
233 |
} else |
|
234 |
return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id); |
|
235 |
}
|
|
236 |
||
237 |
static SYSFS_GET_FUNCTION(pcidriver_show_umem_entry) |
|
238 |
{
|
|
239 |
return 0; |
|
240 |
}
|
|
241 |
||
242 |
||
243 |
#ifdef ENABLE_IRQ
|
|
244 |
static DEVICE_ATTR(irq_count, S_IRUGO, pcidriver_show_irq_count, NULL); |
|
245 |
static DEVICE_ATTR(irq_queues, S_IRUGO, pcidriver_show_irq_queues, NULL); |
|
246 |
#endif
|
|
247 |
||
248 |
static DEVICE_ATTR(mmap_mode, 0664, pcidriver_show_mmap_mode, pcidriver_store_mmap_mode); |
|
249 |
static DEVICE_ATTR(mmap_area, 0664, pcidriver_show_mmap_area, pcidriver_store_mmap_area); |
|
250 |
static DEVICE_ATTR(kmem_count, 0444, pcidriver_show_kmem_count, NULL); |
|
251 |
static DEVICE_ATTR(kbuffers, 0444, pcidriver_show_kbuffers, NULL); |
|
252 |
static DEVICE_ATTR(kmem_alloc, 0220, NULL, pcidriver_store_kmem_alloc); |
|
253 |
static DEVICE_ATTR(kmem_free, 0220, NULL, pcidriver_store_kmem_free); |
|
254 |
static DEVICE_ATTR(umappings, 0444, pcidriver_show_umappings, NULL); |
|
255 |
static DEVICE_ATTR(umem_unmap, 0220, NULL, pcidriver_store_umem_unmap); |
|
256 |
||
257 |
int pcidriver_create_sysfs_attributes(pcidriver_privdata_t *privdata) { |
|
258 |
#ifdef ENABLE_IRQ
|
|
259 |
SYSFS_ATTR_CREATE(irq_count); |
|
260 |
SYSFS_ATTR_CREATE(irq_queues); |
|
261 |
#endif
|
|
262 |
||
263 |
SYSFS_ATTR_CREATE(mmap_mode); |
|
264 |
SYSFS_ATTR_CREATE(mmap_area); |
|
265 |
SYSFS_ATTR_CREATE(kmem_count); |
|
266 |
SYSFS_ATTR_CREATE(kmem_alloc); |
|
267 |
SYSFS_ATTR_CREATE(kmem_free); |
|
268 |
SYSFS_ATTR_CREATE(kbuffers); |
|
269 |
SYSFS_ATTR_CREATE(umappings); |
|
270 |
SYSFS_ATTR_CREATE(umem_unmap); |
|
271 |
||
272 |
return 0; |
|
273 |
}
|
|
274 |
||
275 |
void pcidriver_remove_sysfs_attributes(pcidriver_privdata_t *privdata) { |
|
276 |
#ifdef ENABLE_IRQ
|
|
277 |
SYSFS_ATTR_REMOVE(irq_count); |
|
278 |
SYSFS_ATTR_REMOVE(irq_queues); |
|
279 |
#endif
|
|
280 |
||
281 |
SYSFS_ATTR_REMOVE(mmap_mode); |
|
282 |
SYSFS_ATTR_REMOVE(mmap_area); |
|
283 |
SYSFS_ATTR_REMOVE(kmem_count); |
|
284 |
SYSFS_ATTR_REMOVE(kmem_alloc); |
|
285 |
SYSFS_ATTR_REMOVE(kmem_free); |
|
286 |
SYSFS_ATTR_REMOVE(kbuffers); |
|
287 |
SYSFS_ATTR_REMOVE(umappings); |
|
288 |
SYSFS_ATTR_REMOVE(umem_unmap); |
|
289 |
}
|
|
290 |
||
291 |
/**
|
|
292 |
*
|
|
293 |
* Removes the file from sysfs and frees the allocated (kstrdup()) memory.
|
|
294 |
*
|
|
295 |
*/
|
|
296 |
void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct device_attribute *sysfs_attr) |
|
297 |
{
|
|
298 |
device_remove_file(privdata->class_dev, sysfs_attr); |
|
299 |
kfree(sysfs_attr->attr.name); |
|
300 |
}
|
|
301 |
||
302 |
/**
|
|
303 |
*
|
|
304 |
* Initializes the sysfs attributes for an kmem/umem-entry
|
|
305 |
*
|
|
306 |
*/
|
|
307 |
static int _pcidriver_sysfs_initialize(pcidriver_privdata_t *privdata, int id, struct device_attribute *sysfs_attr, const char *fmtstring, SYSFS_GET_FUNCTION((*callback))) |
|
308 |
{
|
|
309 |
/* sysfs attributes for kmem buffers don’t make sense before 2.6.13, as
|
|
310 |
we have no mmap support before */
|
|
311 |
char namebuffer[16]; |
|
312 |
||
313 |
/* allocate space for the name of the attribute */
|
|
314 |
snprintf(namebuffer, sizeof(namebuffer), fmtstring, id); |
|
315 |
||
316 |
if ((sysfs_attr->attr.name = kstrdup(namebuffer, GFP_KERNEL)) == NULL) |
|
317 |
return -ENOMEM; |
|
318 |
||
319 |
sysfs_attr->attr.mode = S_IRUGO; |
|
320 |
sysfs_attr->show = callback; |
|
321 |
sysfs_attr->store = NULL; |
|
322 |
||
323 |
/* name and add attribute */
|
|
324 |
if (device_create_file(privdata->class_dev, sysfs_attr) != 0) |
|
325 |
return -ENXIO; /* Device not configured. Not the really best choice, but hm. */ |
|
326 |
||
327 |
return 0; |
|
328 |
}
|
|
329 |
||
330 |
int pcidriver_sysfs_initialize_kmem(pcidriver_privdata_t *privdata, int id, struct device_attribute *sysfs_attr) |
|
331 |
{
|
|
332 |
return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "kbuf%d", pcidriver_show_kmem_entry); |
|
333 |
}
|
|
334 |
||
335 |
int pcidriver_sysfs_initialize_umem(pcidriver_privdata_t *privdata, int id, struct device_attribute *sysfs_attr) |
|
336 |
{
|
|
337 |
return _pcidriver_sysfs_initialize(privdata, id, sysfs_attr, "umem%d", pcidriver_show_umem_entry); |
|
338 |
}
|