Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
F
FMC Bus
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
FMC Bus
Commits
7f523503
Commit
7f523503
authored
Apr 05, 2013
by
Alessandro Rubini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fmc-fakedev and doc: the module is multi-mezzanine
Signed-off-by:
Alessandro Rubini
<
rubini@gnudd.com
>
parent
14319935
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
78 additions
and
33 deletions
+78
-33
fmc-bus.in
doc/fmc-bus.in
+24
-3
fmc-fakedev.c
kernel/fmc-fakedev.c
+54
-30
No files found.
doc/fmc-bus.in
View file @
7f523503
...
...
@@ -592,14 +592,16 @@ using the kernel's GPIO mechanisms.
@node fmc-fakedev
@section fmc-fakedev
This package includes a software-only device, called @t{fmc-fakedev}.
This package includes a software-only device, called @t{fmc-fakedev},
which is able to register up to 4 mezzanines (by default it registers one).
Unlike the @sc{spec} driver, which creates an @sc{fmc} device for each
PCI cards it manages, this module creates a single instance of its
device
.
set of mezzanines
.
It is meant as the simplest possible example of how a driver should be
written, and it includes a fake @sc{eeprom} image (built using the
tools described in @ref{FMC Identification}).
tools described in @ref{FMC Identification}), which by default is
replicated for each fake mezzanine.
You can also use this device to verify the match algorithms, by
asking it to test your own @sc{eeprom} image. You can provide the image by
...
...
@@ -624,6 +626,25 @@ overwritten starting at offset 0, the module will unregister and
register again the @sc{fmc} device. This is shown later, in
section @ref{fmc-write-eeprom}.
In order to register more than one mezzanine, you can use module parameters:
@table @code
@item ndev=<number>
Ask for a number of devices. By default it registers one
device or as many as @sc{eeprom} file names it receives.
@item eeprom=<name>[,<name>]
Name of the @sc{eeprom} images to be faked in the mezzanine devices.
You can pass up to 4 comma-separated names; empty names or
trailing unspecified names will select the default built-in
@sc{eeprom} image. If you specify more than one @sc{eeprom} name,
the module will automatically register more than one mezzanine.
@end table
@c ==========================================================================
@node FMC Device Incompatibilities
@section FMC Device Incompatibilities
...
...
kernel/fmc-fakedev.c
View file @
7f523503
...
...
@@ -13,12 +13,20 @@
#include <linux/workqueue.h>
#include <linux/fmc.h>
static
char
*
ff_eeprom
;
module_param_named
(
eeprom
,
ff_eeprom
,
charp
,
0444
);
#define FF_EEPROM_SIZE 8192
/* The standard eeprom size */
#define FF_MAX_MEZZANINES 4
/* Fakes a multi-mezzanine carrier */
/* Lazily, don't support the "standard" module parameters */
/* The user can pass up to 4 names of eeprom images to load */
static
char
*
ff_eeprom
[
FF_MAX_MEZZANINES
];
static
int
ff_nr_eeprom
;
module_param_array_named
(
eeprom
,
ff_eeprom
,
charp
,
&
ff_nr_eeprom
,
0444
);
/* The user can ask for a multi-mezzanine carrier, with the default eeprom */
static
int
ff_nr_dev
=
1
;
module_param_named
(
ndev
,
ff_nr_dev
,
int
,
0444
);
#define FF_EEPROM_SIZE 8192
/* Lazily, don't support the "standard" module parameters */
/*
* Eeprom built from these commands:
...
...
@@ -28,7 +36,8 @@ module_param_named(eeprom, ff_eeprom, charp, 0444);
gensdbfs . ../fake-eeprom.bin
*/
static
char
ff_eeimg
[
FF_EEPROM_SIZE
]
=
{
static
char
ff_eeimg
[
FF_MAX_MEZZANINES
][
FF_EEPROM_SIZE
]
=
{
{
0x01
,
0x00
,
0x00
,
0x01
,
0x00
,
0x0c
,
0x00
,
0xf2
,
0x01
,
0x0b
,
0x00
,
0xb2
,
0x86
,
0x87
,
0xcb
,
0x66
,
0x61
,
0x6b
,
0x65
,
0x2d
,
0x76
,
0x65
,
0x6e
,
0x64
,
0x6f
,
0x72
,
0xd7
,
0x66
,
0x61
,
0x6b
,
0x65
,
0x2d
,
0x64
,
0x65
,
0x73
,
0x69
,
...
...
@@ -67,10 +76,11 @@ static char ff_eeimg[FF_EEPROM_SIZE] = {
0x00
,
0x00
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x00
,
0x49
,
0x50
,
0x4d
,
0x49
,
0x2d
,
0x46
,
0x52
,
0x55
,
0x20
,
0x20
,
0x20
,
0x20
,
0x20
,
0x20
,
0x20
,
0x20
,
0x20
,
0x20
,
0x20
,
0x01
,
0x66
,
0x61
,
0x6b
,
0x65
,
0x0a
,
},
};
struct
ff_dev
{
struct
fmc_device
fmc
;
struct
fmc_device
fmc
[
FF_MAX_MEZZANINES
]
;
struct
device
dev
;
struct
delayed_work
work
;
};
...
...
@@ -127,7 +137,7 @@ static void ff_work_fn(struct work_struct *work)
struct
ff_dev
*
ff
=
container_of
(
dw
,
struct
ff_dev
,
work
);
int
ret
;
fmc_device_unregister
(
&
ff
->
fmc
);
fmc_device_unregister
_n
(
ff
->
fmc
,
ff_nr_dev
);
device_unregister
(
&
ff
->
dev
);
ff_current_dev
=
NULL
;
...
...
@@ -136,7 +146,7 @@ static void ff_work_fn(struct work_struct *work)
pr_warning
(
"%s: can't re-create FMC device
\n
"
,
__func__
);
return
;
}
ret
=
fmc_device_register
(
&
ff
->
fmc
);
ret
=
fmc_device_register
_n
(
ff
->
fmc
,
ff_nr_dev
);
if
(
ret
<
0
)
{
device_unregister
(
&
ff
->
dev
);
pr_warning
(
"%s: can't re-register FMC device
\n
"
,
__func__
);
...
...
@@ -154,7 +164,7 @@ int ff_eeprom_read(struct fmc_device *fmc, uint32_t offset,
return
-
EINVAL
;
if
(
offset
+
size
>
FF_EEPROM_SIZE
)
size
=
FF_EEPROM_SIZE
-
offset
;
memcpy
(
buf
,
f
f_eeimg
+
offset
,
size
);
memcpy
(
buf
,
f
mc
->
eeprom
+
offset
,
size
);
return
size
;
}
...
...
@@ -168,7 +178,7 @@ int ff_eeprom_write(struct fmc_device *fmc, uint32_t offset,
if
(
offset
+
size
>
FF_EEPROM_SIZE
)
size
=
FF_EEPROM_SIZE
-
offset
;
pr_info
(
"%s: size %zi
\n
"
,
__func__
,
size
);
memcpy
(
f
f_eeimg
+
offset
,
buf
,
size
);
memcpy
(
f
mc
->
eeprom
+
offset
,
buf
,
size
);
schedule_delayed_work
(
&
ff
->
work
,
HZ
*
2
);
/* remove, replug, in 2s */
return
size
;
}
...
...
@@ -221,10 +231,7 @@ static struct fmc_device ff_template_fmc = {
.
owner
=
THIS_MODULE
,
.
carrier_name
=
"fake"
,
.
device_id
=
0xf001
,
/* fool */
.
eeprom
=
ff_eeimg
,
.
eeprom_addr
=
0x50
,
.
eeprom_len
=
sizeof
(
ff_eeimg
),
.
nr_slots
=
1
,
.
eeprom_len
=
sizeof
(
ff_eeimg
[
0
]),
.
memlen
=
0x1000
,
/* 4k, to show something */
.
op
=
&
ff_fmc_operations
,
.
hwdev
=
NULL
,
/* filled at creation time */
...
...
@@ -234,7 +241,7 @@ static struct fmc_device ff_template_fmc = {
static
struct
ff_dev
*
ff_dev_create
(
void
)
{
struct
ff_dev
*
ff
;
int
ret
;
int
i
,
ret
;
ff
=
kzalloc
(
sizeof
(
*
ff
),
GFP_KERNEL
);
if
(
!
ff
)
...
...
@@ -249,12 +256,19 @@ static struct ff_dev *ff_dev_create(void)
return
ERR_PTR
(
ret
);
}
/* Create an fmc structure that refers to this new "hw" device */
ff
->
fmc
=
ff_template_fmc
;
ff
->
fmc
.
hwdev
=
&
ff
->
dev
;
ff
->
fmc
.
carrier_data
=
ff
;
ff_template_fmc
.
device_id
++
;
/* for next time */
/* Create fmc structures that refers to this new "hw" device */
for
(
i
=
0
;
i
<
ff_nr_dev
;
i
++
)
{
ff
->
fmc
[
i
]
=
ff_template_fmc
;
ff
->
fmc
[
i
].
hwdev
=
&
ff
->
dev
;
ff
->
fmc
[
i
].
carrier_data
=
ff
;
ff
->
fmc
[
i
].
nr_slots
=
ff_nr_dev
;
/* the following fields are different for each slot */
ff
->
fmc
[
i
].
eeprom
=
ff_eeimg
[
i
];
ff
->
fmc
[
i
].
eeprom_addr
=
0x50
+
2
*
i
;
ff
->
fmc
[
i
].
slot_id
=
i
;
/* increment the identifier, each must be different */
ff_template_fmc
.
device_id
++
;
}
INIT_DELAYED_WORK
(
&
ff
->
work
,
ff_work_fn
);
return
ff
;
}
...
...
@@ -264,27 +278,37 @@ int ff_init(void)
{
struct
ff_dev
*
ff
;
const
struct
firmware
*
fw
;
int
len
,
ret
=
0
;
int
i
,
len
,
ret
=
0
;
/* Replicate the default eeprom for the max number of mezzanines */
for
(
i
=
1
;
i
<
FF_MAX_MEZZANINES
;
i
++
)
memcpy
(
ff_eeimg
[
i
],
ff_eeimg
[
0
],
sizeof
(
ff_eeimg
[
0
]));
if
(
ff_nr_eeprom
>
ff_nr_dev
)
ff_nr_dev
=
ff_nr_eeprom
;
ff
=
ff_dev_create
();
if
(
IS_ERR
(
ff
))
return
PTR_ERR
(
ff
);
/* If the user passed "eeprom=" as a parameter, fetch it */
if
(
ff_eeprom
)
{
ret
=
request_firmware
(
&
fw
,
ff_eeprom
,
&
ff
->
dev
);
/* If the user passed "eeprom=" as a parameter, fetch them */
for
(
i
=
0
;
i
<
ff_nr_eeprom
;
i
++
)
{
if
(
!
strlen
(
ff_eeprom
[
i
]))
continue
;
ret
=
request_firmware
(
&
fw
,
ff_eeprom
[
i
],
&
ff
->
dev
);
if
(
ret
<
0
)
{
dev_err
(
&
ff
->
dev
,
"
Can't load
\"
%s
\"
(error %i)
\n
"
,
ff_eeprom
,
-
ret
);
dev_err
(
&
ff
->
dev
,
"
Mezzanine %i: can't load
\"
%s
\"
"
"(error %i)
\n
"
,
i
,
ff_eeprom
[
i
]
,
-
ret
);
}
else
{
len
=
min_t
(
size_t
,
fw
->
size
,
(
size_t
)
FF_EEPROM_SIZE
);
memcpy
(
ff_eeimg
,
fw
->
data
,
len
);
memcpy
(
ff_eeimg
[
i
]
,
fw
->
data
,
len
);
release_firmware
(
fw
);
dev_info
(
&
ff
->
dev
,
"Mezzanine %i: eeprom
\"
%s
\"\n
"
,
i
,
ff_eeprom
[
i
]);
}
}
ret
=
fmc_device_register
(
&
ff
->
fmc
);
ret
=
fmc_device_register
_n
(
ff
->
fmc
,
ff_nr_dev
);
if
(
ret
)
{
device_unregister
(
&
ff
->
dev
);
return
ret
;
...
...
@@ -297,7 +321,7 @@ void ff_exit(void)
{
if
(
ff_current_dev
)
{
cancel_delayed_work_sync
(
&
ff_current_dev
->
work
);
fmc_device_unregister
(
&
ff_current_dev
->
fmc
);
fmc_device_unregister
_n
(
ff_current_dev
->
fmc
,
ff_nr_dev
);
device_unregister
(
&
ff_current_dev
->
dev
);
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment