-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathhpal.h
More file actions
341 lines (275 loc) · 9.82 KB
/
hpal.h
File metadata and controls
341 lines (275 loc) · 9.82 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 - 2020 DisplayLink (UK) Ltd.
*/
#ifndef __MAUSB_HPAL_H__
#define __MAUSB_HPAL_H__
#include <linux/miscdevice.h>
#include <linux/scatterlist.h> /* needed for 4.4 */
#include <linux/suspend.h>
#include <linux/usb.h>
#include "ip_link.h"
#include "mausb_address.h"
#include "mausb_event.h"
#define MAUSB_CONTROL_SETUP_SIZE 8
#define MAUSB_BUSY_RETRIES_COUNT 3
#define MAUSB_HEARTBEAT_TIMEOUT_MS 1000
#define MAUSB_CLIENT_STOPPED_TIMEOUT_MS 3000
#define MAUSB_MAX_RECEIVE_FAILURES 3
#define MAUSB_MAX_MISSED_HEARTBEATS 3
#define MAUSB_TRANSFER_RESERVED 0
#define MAUSB_CHANNEL_MAP_LENGTH 4
extern struct mss mss;
extern struct mausb_hcd *mhcd;
extern struct miscdevice mausb_host_dev;
enum mausb_isoch_header_format_size {
MAUSB_ISOCH_SHORT_FORMAT_SIZE = 4,
MAUSB_ISOCH_STANDARD_FORMAT_SIZE = 8,
MAUSB_ISOCH_LONG_FORMAT_SIZE = 12,
};
struct mausb_completion {
struct list_head list_entry;
struct completion *completion_event;
struct mausb_event *mausb_event;
u64 event_id;
};
struct mausb_mss_rings_events {
atomic_t mausb_stop_reading_ring_events;
struct completion mausb_ring_has_events;
};
struct mss {
bool deinit_in_progress;
spinlock_t lock; /* Protect mss structure */
u64 ring_buffer_id;
struct completion empty;
struct completion client_stopped;
bool client_connected;
struct timer_list heartbeat_timer;
u8 missed_heartbeats;
struct list_head madev_list;
atomic_t num_of_transitions_to_sleep;
struct list_head available_ring_buffers;
struct mausb_mss_rings_events rings_events;
struct mausb_events_notification events[MAUSB_MAX_NUM_OF_MA_DEVS];
};
struct mausb_device {
struct mausb_device_address dev_addr;
struct net *net_ns;
struct mausb_ring_buffer *ring_buffer;
struct list_head list_entry;
struct mausb_ip_ctx *mgmt_channel;
struct mausb_ip_ctx *ctrl_channel;
struct mausb_ip_ctx *bulk_channel;
struct mausb_ip_ctx *isoch_channel;
struct mausb_ip_ctx *channel_map[MAUSB_CHANNEL_MAP_LENGTH];
struct work_struct work;
struct work_struct socket_disconnect_work;
struct work_struct hcd_disconnect_work;
struct work_struct madev_delete_work;
struct work_struct ping_work;
struct work_struct heartbeat_work;
struct workqueue_struct *workq;
struct kref refcount;
/* Set on port change event after cap resp */
u8 dev_type;
u8 dev_speed;
u8 lse;
u8 madev_addr;
u8 dev_connected;
u8 port_number;
u16 id;
u64 event_id;
spinlock_t event_id_lock; /* Lock event ID increments */
struct list_head completion_events;
spinlock_t completion_events_lock; /* Lock completion events */
struct completion user_finished_event;
u16 num_of_user_events;
u16 num_of_completed_events;
spinlock_t num_of_user_events_lock; /* Lock user events count */
struct timer_list connection_timer;
u8 receive_failures_num;
spinlock_t connection_timer_lock; /* Lock connection timer */
atomic_t unresponsive_client;
atomic_t num_of_usb_devices;
};
struct mausb_urb_ctx *mausb_find_urb_in_tree(struct urb *urb);
struct mausb_urb_ctx *mausb_unlink_and_delete_urb_from_tree(struct urb *urb,
int status);
struct mausb_device *mausb_get_dev_from_addr_unsafe(u8 madev_addr);
static inline u64 mausb_event_id(struct mausb_device *dev)
{
unsigned long flags;
u64 val;
spin_lock_irqsave(&dev->event_id_lock, flags);
val = ++(dev->event_id);
spin_unlock_irqrestore(&dev->event_id_lock, flags);
return val;
}
int mausb_initiate_dev_connection(struct mausb_device_address device_address,
u8 madev_address);
int mausb_enqueue_event_from_user(u8 madev_addr, u16 num_of_events,
u16 num_of_completed);
int mausb_enqueue_event_to_user(struct mausb_device *dev,
struct mausb_event *event);
int mausb_data_req_enqueue_event(struct mausb_device *dev, u16 ep_handle,
struct urb *request);
int mausb_signal_event(struct mausb_device *dev, struct mausb_event *event,
u64 event_id);
int mausb_insert_urb_in_tree(struct urb *urb, bool link_urb_to_ep);
static inline void mausb_insert_event(struct mausb_device *dev,
struct mausb_completion *event)
{
unsigned long flags;
spin_lock_irqsave(&dev->completion_events_lock, flags);
list_add_tail(&event->list_entry, &dev->completion_events);
spin_unlock_irqrestore(&dev->completion_events_lock, flags);
}
static inline void mausb_remove_event(struct mausb_device *dev,
struct mausb_completion *event)
{
unsigned long flags;
spin_lock_irqsave(&dev->completion_events_lock, flags);
list_del(&event->list_entry);
spin_unlock_irqrestore(&dev->completion_events_lock, flags);
}
void mausb_release_ma_dev_async(struct kref *kref);
void mausb_on_madev_connected(struct mausb_device *dev);
void mausb_complete_request(struct urb *urb, u32 actual_length, int status);
void mausb_complete_urb(struct mausb_event *event);
void mausb_reset_connection_timer(struct mausb_device *dev);
void mausb_reset_heartbeat_cnt(void);
void mausb_release_event_resources(struct mausb_event *event);
void mausb_initialize_mss(void);
void mausb_deinitialize_mss(void);
int mausb_register_power_state_listener(void);
void mausb_unregister_power_state_listener(void);
void mausb_init_standard_ep_descriptor(struct ma_usb_ephandlereq_desc_std *
std_desc,
struct usb_endpoint_descriptor *
usb_std_desc);
void mausb_init_superspeed_ep_descriptor(struct ma_usb_ephandlereq_desc_ss *
ss_desc,
struct usb_endpoint_descriptor *
usb_std_desc,
struct usb_ss_ep_comp_descriptor *
usb_ss_desc);
int mausb_send_data(struct mausb_device *dev, enum mausb_channel channel_num,
struct mausb_kvec_data_wrapper *data);
int mausb_send_transfer_ack(struct mausb_device *dev,
struct mausb_event *event);
int mausb_send_data_msg(struct mausb_device *dev, struct mausb_event *event);
int mausb_receive_data_msg(struct mausb_device *dev, struct mausb_event *event);
int mausb_add_data_chunk(void *buffer, u32 buffer_size,
struct list_head *chunks_list);
int mausb_init_data_wrapper(struct mausb_kvec_data_wrapper *data,
struct list_head *chunks_list,
u32 num_of_data_chunks);
void mausb_cleanup_chunks_list(struct list_head *chunks_list);
static inline bool mausb_ctrl_transfer(struct ma_usb_hdr_common *hdr)
{
return (hdr->data.t_flags & MA_USB_DATA_TFLAGS_TRANSFER_TYPE_MASK) ==
MA_USB_DATA_TFLAGS_TRANSFER_TYPE_CTRL;
}
static inline bool mausb_isoch_transfer(struct ma_usb_hdr_common *hdr)
{
return (hdr->data.t_flags & MA_USB_DATA_TFLAGS_TRANSFER_TYPE_MASK) ==
MA_USB_DATA_TFLAGS_TRANSFER_TYPE_ISOCH;
}
static inline bool mausb_ctrl_data_event(struct mausb_event *event)
{
return event->data.transfer_type ==
MA_USB_DATA_TFLAGS_TRANSFER_TYPE_CTRL;
}
static inline bool mausb_isoch_data_event(struct mausb_event *event)
{
return event->data.transfer_type ==
MA_USB_DATA_TFLAGS_TRANSFER_TYPE_ISOCH;
}
/* usb to mausb transfer type */
static inline
u8 mausb_transfer_type_from_usb(struct usb_endpoint_descriptor *epd)
{
return (u8)usb_endpoint_type(epd) << 3;
}
static inline u8 mausb_transfer_type_from_hdr(struct ma_usb_hdr_common *hdr)
{
return hdr->data.t_flags & MA_USB_DATA_TFLAGS_TRANSFER_TYPE_MASK;
}
static inline
enum mausb_channel mausb_transfer_type_to_channel(u8 transfer_type)
{
return transfer_type >> 3;
}
void mausb_ip_callback(void *ctx, enum mausb_channel channel,
enum mausb_link_action action, int status, void *data);
struct mausb_data_iter {
u32 length;
void *buffer;
u32 buffer_len;
u32 offset;
struct scatterlist *sg;
struct sg_mapping_iter sg_iter;
bool sg_started;
unsigned int num_sgs;
unsigned int flags;
};
struct mausb_payload_chunk {
struct list_head list_entry;
struct kvec kvec;
};
int mausb_data_iterator_read(struct mausb_data_iter *iterator,
u32 byte_num,
struct list_head *data_chunks_list,
u32 *data_chunks_num);
u32 mausb_data_iterator_length(struct mausb_data_iter *iterator);
u32 mausb_data_iterator_write(struct mausb_data_iter *iterator, void *buffer,
u32 length);
void mausb_init_data_iterator(struct mausb_data_iter *iterator,
void *buffer, u32 buffer_len,
struct scatterlist *sg, unsigned int num_sgs,
bool direction);
void mausb_reset_data_iterator(struct mausb_data_iter *iterator);
void mausb_uninit_data_iterator(struct mausb_data_iter *iterator);
void mausb_data_iterator_seek(struct mausb_data_iter *iterator, u32 seek_delta);
struct mausb_ring_buffer {
atomic_t mausb_ring_events;
atomic_t mausb_completed_user_events;
struct mausb_event *to_user_buffer;
int head;
int tail;
spinlock_t lock; /* Protect ring buffer */
u64 id;
struct mausb_event *from_user_buffer;
int current_from_user;
struct list_head list_entry;
bool buffer_full;
};
int mausb_ring_buffer_init(struct mausb_ring_buffer *ring);
int mausb_ring_buffer_put(struct mausb_ring_buffer *ring,
struct mausb_event *event);
int mausb_ring_buffer_move_tail(struct mausb_ring_buffer *ring, u32 count);
void mausb_ring_buffer_cleanup(struct mausb_ring_buffer *ring);
void mausb_ring_buffer_destroy(struct mausb_ring_buffer *ring);
void mausb_cleanup_ring_buffer_event(struct mausb_event *event);
void mausb_disconect_event_unsafe(struct mausb_ring_buffer *ring,
uint8_t madev_addr);
static inline unsigned int mausb_get_page_order(unsigned int num_of_elems,
unsigned int elem_size)
{
unsigned int num_of_pages = DIV_ROUND_UP(num_of_elems * elem_size,
PAGE_SIZE);
unsigned int order = (unsigned int)ilog2(num_of_pages) +
(is_power_of_2(num_of_pages) ? 0 : 1);
return order;
}
static inline
struct mausb_event *mausb_ring_current_from_user(struct mausb_ring_buffer *ring)
{
return ring->from_user_buffer + ring->current_from_user;
}
static inline void mausb_ring_next_from_user(struct mausb_ring_buffer *ring)
{
ring->current_from_user = (ring->current_from_user + 1) &
(MAUSB_RING_BUFFER_SIZE - 1);
}
#endif /* __MAUSB_HPAL_H__ */