Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
S
Simple VME FMC Carrier SVEC
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
14
Issues
14
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
Simple VME FMC Carrier SVEC
Commits
10466a84
Commit
10466a84
authored
Sep 29, 2017
by
Federico Vaga
Committed by
Federico Vaga
Sep 29, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kernel: add minimum char device support
Signed-off-by:
Federico Vaga
<
federico.vaga@vaga.pv.it
>
parent
85c022cb
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
125 additions
and
3 deletions
+125
-3
svec-core.c
kernel/svec-core.c
+125
-3
No files found.
kernel/svec-core.c
View file @
10466a84
...
...
@@ -12,13 +12,23 @@
* Driver for SVEC (Simple VME FMC carrier) board.
*/
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <vmebus.h>
#define SVEC_MINOR_MAX (64)
static
DECLARE_BITMAP
(
svec_minors
,
SVEC_MINOR_MAX
);
static
dev_t
basedev
;
static
struct
cdev
svec_cdev
;
static
struct
class
*
svec_class
;
/**
* struct svec_dev - SVEC instance
* @vdev VME device instance
...
...
@@ -27,6 +37,80 @@ struct svec_dev {
struct
device
dev
;
};
static
inline
struct
svec_dev
*
to_svec_dev
(
struct
device
*
ptr
)
{
return
container_of
(
ptr
,
struct
svec_dev
,
dev
);
}
static
inline
int
svec_minor_get
(
void
)
{
int
minor
;
minor
=
find_first_zero_bit
(
svec_minors
,
SVEC_MINOR_MAX
);
set_bit
(
minor
,
svec_minors
);
return
minor
;
}
static
inline
void
svec_minor_put
(
unsigned
int
minor
)
{
clear_bit
(
minor
,
svec_minors
);
}
/**
* It sets the private data and check that only one user at
* time access this file
*/
static
int
svec_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
return
0
;
}
/**
* It actually flash the bitstream on the FGPA
*/
static
int
svec_close
(
struct
inode
*
inode
,
struct
file
*
f
)
{
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
return
0
;
}
/**
* It creates a local copy of the user buffer
*/
static
ssize_t
svec_write
(
struct
file
*
f
,
const
char
__user
*
buf
,
size_t
count
,
loff_t
*
offp
)
{
pr_info
(
"%s:%d
\n
"
,
__func__
,
__LINE__
);
if
(
!
count
)
return
-
EINVAL
;
return
count
;
}
/**
* Char device operation to provide bitstream
*/
static
const
struct
file_operations
svec_fops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
svec_open
,
.
release
=
svec_close
,
.
write
=
svec_write
,
};
static
void
svec_release
(
struct
device
*
dev
)
{
struct
svec_dev
*
svec
=
to_svec_dev
(
dev
);
svec_minor_put
(
MINOR
(
dev
->
devt
));
kfree
(
svec
);
}
/**
* It initialize a new SVEC instance
...
...
@@ -42,11 +126,14 @@ static int svec_probe(struct device *dev, unsigned int ndev)
svec
=
kzalloc
(
sizeof
(
struct
svec_dev
),
GFP_KERNEL
);
if
(
!
svec
)
{
dev_err
(
dev
,
"Cannot allocate memory for svec card struct
\n
"
);
return
-
ENOMEM
;
goto
err
;
}
dev_set_name
(
&
svec
->
dev
,
"svec.%d"
,
vdev
->
slot
);
svec
->
dev
.
class
=
svec_class
;
svec
->
dev
.
devt
=
basedev
+
svec_minor_get
();
svec
->
dev
.
parent
=
&
vdev
->
dev
;
svec
->
dev
.
release
=
svec_release
;
dev_set_drvdata
(
&
vdev
->
dev
,
svec
);
err
=
device_register
(
&
svec
->
dev
);
...
...
@@ -56,7 +143,10 @@ static int svec_probe(struct device *dev, unsigned int ndev)
return
0
;
err_dev_reg:
svec_minor_put
(
MINOR
(
svec
->
dev
.
devt
));
kfree
(
svec
);
err:
dev_err
(
dev
,
"Failed to register SVEC device
\n
"
);
return
err
;
}
...
...
@@ -66,7 +156,6 @@ static int svec_remove(struct device *pdev, unsigned int ndev)
struct
svec_dev
*
svec
=
dev_get_drvdata
(
pdev
);
device_unregister
(
&
svec
->
dev
);
kfree
(
svec
);
return
0
;
}
...
...
@@ -99,12 +188,45 @@ static struct vme_driver svec_driver = {
static
int
__init
svec_init
(
void
)
{
return
vme_register_driver
(
&
svec_driver
,
0
);
int
err
=
0
;
svec_class
=
class_create
(
THIS_MODULE
,
"svec"
);
if
(
IS_ERR_OR_NULL
(
svec_class
))
{
err
=
PTR_ERR
(
svec_class
);
goto
err_cls
;
}
/* Allocate a char device region for devices, CPUs and slots */
err
=
alloc_chrdev_region
(
&
basedev
,
0
,
SVEC_MINOR_MAX
,
"svec"
);
if
(
err
)
goto
err_chrdev_alloc
;
cdev_init
(
&
svec_cdev
,
&
svec_fops
);
svec_cdev
.
owner
=
THIS_MODULE
;
err
=
cdev_add
(
&
svec_cdev
,
basedev
,
SVEC_MINOR_MAX
);
if
(
err
)
goto
err_cdev_add
;
err
=
vme_register_driver
(
&
svec_driver
,
0
);
if
(
err
)
goto
err_drv_reg
;
return
0
;
err_drv_reg:
cdev_del
(
&
svec_cdev
);
err_cdev_add:
unregister_chrdev_region
(
basedev
,
SVEC_MINOR_MAX
);
err_chrdev_alloc:
class_destroy
(
svec_class
);
err_cls:
return
err
;
}
static
void
__exit
svec_exit
(
void
)
{
vme_unregister_driver
(
&
svec_driver
);
cdev_del
(
&
svec_cdev
);
unregister_chrdev_region
(
basedev
,
SVEC_MINOR_MAX
);
class_destroy
(
svec_class
);
}
module_init
(
svec_init
);
...
...
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