-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathusb_can_api.c
148 lines (141 loc) · 4.71 KB
/
usb_can_api.c
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
146
147
148
/**
* Copyright (C) 2019 Shymaxtic
*
* This file is part of CANUSBdriver.
*
* CANUSBdriver 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.
*
* CANUSBdriver 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 CANUSBdriver. If not, see <http://www.gnu.org/licenses/>.
*/
#include "usb_can_api.h"
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
// callback function when finish writing bulk .
static void usb_can_write_bulk_callback(struct urb *urb) {
struct usb_can_dev_t *dev = urb->context;
// sync/ asyn unlink faults are not errors.
if (urb->status && !(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN)) {
dev_dbg(&dev->uif->dev,
"%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
}
/* free up our allocated buffer */
usb_free_coherent(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
}
/**
* request data from usb device.
* the performance currently is not perfect.
**/
int usb_can_request_data(int type, struct usb_can_dev_t* dev) {
int ret = 0;
struct urb *urb = NULL;
usb_can_packet_t* buf = NULL;
int rcvLen = 0;
if (!dev) {
ret = -ENOMEM;
goto exit;
}
// creat an urb
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
ret = -ENOMEM;
goto exit;
}
// create buffer to receive or transmit data.
buf = usb_alloc_coherent(dev->udev, sizeof(usb_can_packet_t), GFP_KERNEL, &urb->transfer_dma); //TODO: read transfer_dma
if (!buf) {
ret = -ENOMEM;
goto error_urb;
}
buf->u8type = type;
// Transmition phase.---
// fill the urb
usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, sizeof(usb_can_packet_t), usb_can_write_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
// send the data out the bulk port.
ret = usb_submit_urb(urb, GFP_KERNEL) ;
if (ret) {
pr_err("%s - Failed to submit write urb with error %d", __FUNCTION__, ret);
goto error;
}
usb_free_urb(urb);
// Receive phase.---
ret = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer,
min(dev->bulk_in_size, sizeof(usb_can_packet_t)),
(int *) &rcvLen, HZ*10);
// TODO: check mismatch len.
exit:
return ret;
error_urb:
usb_free_urb(urb);
return ret;
error:
usb_free_coherent(dev->udev, sizeof(usb_can_packet_t), buf, urb->transfer_dma);
// kfree(buf); // TODO: check if need this line?
usb_free_urb(urb);
return ret;
}
/**
* This function must be called in kernel space.
*/
int usb_can_deserialize_to_ioclt_can_frame(ioctl_can_frame_param_t __user* user_params, const uint8_t* in_buff) {
int ret = 0;
usb_can_packet_t rcvPck;
ioctl_can_frame_param_t kernel_params;
if (!user_params || !in_buff) {
ret = -EINVAL;
goto error;
}
memcpy(&rcvPck, in_buff, sizeof(usb_can_packet_t));
// serialize data of usb packet to ioctl_can_frame_param_t
/**
* | frame num (1) | frame info (4 * 13) |
**/
kernel_params.u8frame_nums = rcvPck.au8data[0];
memcpy(kernel_params.frame_info, &rcvPck.au8data[1], sizeof(kernel_params.frame_info));
if (copy_to_user(user_params, &kernel_params, sizeof(ioctl_can_frame_param_t))) {
pr_err("%s - Faild to copy to user %d", __FUNCTION__, ret);
ret = -EFAULT;
goto error;
}
return ret;
error:
return ret;
}
int usb_can_deserialize_to_ioclt_baudrate(uint64_t __user* user_params, const uint8_t* in_buff) {
int ret = 0;
usb_can_packet_t rcvPck;
if (!user_params || !in_buff) {
ret = -EINVAL;
goto error;
}
memcpy(&rcvPck, in_buff, sizeof(usb_can_packet_t));
// serialize data of usb packet to uint64_t baudrate
if (copy_to_user(user_params, rcvPck.au8data, sizeof(uint64_t))) {
pr_err("%s - Faild to copy to user %d", __FUNCTION__, ret);
ret = -EFAULT;
goto error;
}
return ret;
error:
return ret;
}