-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathpciedev_rw_exp.c
More file actions
145 lines (120 loc) · 4.76 KB
/
Copy pathpciedev_rw_exp.c
File metadata and controls
145 lines (120 loc) · 4.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
*Copyright 2016- DESY (Deutsches Elektronen-Synchrotron, www.desy.de)
*
*This file is part of UPCIEDEV driver.
*
*UPCIEDEV is free software: you can redistribute it and/or modify
*it under the terms of the GNU General Public License as published by
*the Free Software Foundation, either version 3 of the License, or
*(at your option) any later version.
*
*UPCIEDEV is distributed in the hope that it will be useful,
*but WITHOUT ANY WARRANTY; without even the implied warranty of
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
*GNU General Public License for more details.
*
*You should have received a copy of the GNU General Public License
*along with UPCIEDEV. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* Author: Ludwig Petrosyan (Email: ludwig.petrosyan@desy.de)
*/
#include <linux/module.h>
#include <linux/fs.h>
//#include <asm/uaccess.h>
#include "pciedev_ufn.h"
#include "read_write_inline.h"
#include "debug_functions.h"
#ifdef DEBUG_TIMING
#define NSEC_FROM_TIMESPEC(_a_timespec_,_a_timespec_end_) \
((u_int64_t)((u_int64_t)((_a_timespec_end_).tv_sec-(_a_timespec_).tv_sec)*1000000000L+\
(u_int64_t)((_a_timespec_end_).tv_nsec - (_a_timespec_).tv_nsec)))
#endif
ssize_t pciedev_read_exp(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
ssize_t retval = 0;
struct pciedev_dev *dev = filp->private_data;
if (!dev->dev_sts){
ERRCT("ERROR: NO DEVICE %d\n", dev->dev_num);
return -ENODEV;
}
if (EnterCritRegion(&dev->dev_mut)){ return -ERESTARTSYS; } /// new
/*Check if it is pread call*/
if (*f_pos != PCIED_FPOS)
{
//printk(KERN_ALERT "PCIEDEV_READ_EXP:PREAD called POS IS 7\n");
u_int64_t llnPos = (u_int64_t)f_pos;
u_int32_t reg_size = (llnPos & PRW_REG_SIZE_MASK) >> PRW_REG_SIZE_SHIFT;
u_int32_t barx_rw = (llnPos & PRW_BAR_MASK) >> PRW_BAR_SHIFT;
u_int32_t offset_rw = (llnPos & PRW_OFFSET_MASK);
CORRECT_REGISTER_SIZE(reg_size, dev->register_size);
retval = pciedev_read_inline(dev, reg_size, MTCA_SIMPLE_READ, barx_rw, offset_rw, buf, count);
retval = sizeof(device_rw);
}else{
device_rw reading;
char* __user pcUserBuffer; // Temporal buffer from user space to store value
if (copy_from_user(&reading, buf, sizeof(device_rw))) { return -EIO; }
pcUserBuffer = (char*)((void*)&((device_rw*)buf)->data_rw);
count = 1;
CORRECT_REGISTER_SIZE(reading.register_size, dev->register_size);
retval = pciedev_read_inline(dev,reading.register_size,MTCA_SIMPLE_READ,reading.barx_rw,
reading.offset_rw,pcUserBuffer, count);
retval = sizeof(device_rw);
}
LeaveCritRegion(&dev->dev_mut);
retval = sizeof(device_rw); // read/write returns sizeof(device_rw) or error
return retval;
}
EXPORT_SYMBOL(pciedev_read_exp);
ssize_t pciedev_write_exp(struct file *a_filp, const char __user *a_buf, size_t count, loff_t *a_f_pos)
{
ssize_t retval = 0;
struct pciedev_dev* dev = a_filp->private_data;
if (!dev->dev_sts){
ERRCT("ERROR: NO DEVICE %d\n", dev->dev_num);
return -EFAULT;
}
if (EnterCritRegion(&dev->dev_mut)){ return -ERESTARTSYS; } /// new
/*Check if it is pwrite call*/
if (*a_f_pos != PCIED_FPOS)
{
u_int64_t llnPos = (u_int64_t)a_f_pos;
u_int32_t reg_size = (llnPos & PRW_REG_SIZE_MASK) >> PRW_REG_SIZE_SHIFT;
u_int32_t barx_rw = (llnPos & PRW_BAR_MASK) >> PRW_BAR_SHIFT;
u_int32_t offset_rw = (llnPos & PRW_OFFSET_MASK);
CORRECT_REGISTER_SIZE(reg_size, dev->register_size);
retval = pciedev_write_inline(dev, reg_size, MTCA_SIMPLE_WRITE, barx_rw, offset_rw, a_buf, NULL, count);
retval = sizeof(device_rw);
}
else
{
device_rw reading;
const char* __user pcUserBuffer; // Temporal buffer from user space to read value
if (copy_from_user(&reading, a_buf, sizeof(device_rw))) {return -EFAULT;}
pcUserBuffer = (const char*)((const void*)&((device_rw*)a_buf)->data_rw);
count = 1;
CORRECT_REGISTER_SIZE(reading.register_size, dev->register_size);
retval = pciedev_write_inline(dev, reading.register_size, MTCA_SIMPLE_WRITE,reading.barx_rw,
reading.offset_rw, pcUserBuffer, NULL, count);
retval = sizeof(device_rw);
}
LeaveCritRegion(&dev->dev_mut);
retval = sizeof(device_rw); // read/write returns sizeof(device_rw) or error
return retval;
}
EXPORT_SYMBOL(pciedev_write_exp);
loff_t pciedev_llseek(struct file *filp, loff_t off, int frm)
{
ssize_t retval = 0;
int minor = 0;
int d_num = 0;
struct pciedev_dev *dev = filp->private_data;
minor = dev->dev_minor;
d_num = dev->dev_num;
filp->f_pos = (loff_t)PCIED_FPOS;
if(!dev->dev_sts){
retval = -EFAULT;
return retval;
}
return (loff_t)PCIED_FPOS;
}