Blame view
drivers/most/most_usb.c
32 KB
1a79f22de staging: most: ad... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
a4198cdf0 Staging: most: ad... |
2 |
/* |
6e01fc777 staging: most: us... |
3 |
* usb.c - Hardware dependent module for USB |
a4198cdf0 Staging: most: ad... |
4 5 |
* * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG |
a4198cdf0 Staging: most: ad... |
6 |
*/ |
a4198cdf0 Staging: most: ad... |
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#include <linux/module.h> #include <linux/fs.h> #include <linux/usb.h> #include <linux/slab.h> #include <linux/init.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/list.h> #include <linux/completion.h> #include <linux/mutex.h> #include <linux/spinlock.h> #include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/sysfs.h> #include <linux/dma-mapping.h> #include <linux/etherdevice.h> #include <linux/uaccess.h> |
b27652753 staging: most: mo... |
24 |
#include <linux/most.h> |
a4198cdf0 Staging: most: ad... |
25 26 27 28 29 30 31 32 33 |
#define USB_MTU 512 #define NO_ISOCHRONOUS_URB 0 #define AV_PACKETS_PER_XACT 2 #define BUF_CHAIN_SIZE 0xFFFF #define MAX_NUM_ENDPOINTS 30 #define MAX_SUFFIX_LEN 10 #define MAX_STRING_LEN 80 #define MAX_BUF_SIZE 0xFFFF |
a4198cdf0 Staging: most: ad... |
34 35 36 |
#define USB_VENDOR_ID_SMSC 0x0424 /* VID: SMSC */ #define USB_DEV_ID_BRDG 0xC001 /* PID: USB Bridge */ |
654f7ec4b staging: most: hd... |
37 |
#define USB_DEV_ID_OS81118 0xCF18 /* PID: USB OS81118 */ |
b50762eaf staging: most: hd... |
38 |
#define USB_DEV_ID_OS81119 0xCF19 /* PID: USB OS81119 */ |
5bf9bd8d1 staging: most: hd... |
39 |
#define USB_DEV_ID_OS81210 0xCF30 /* PID: USB OS81210 */ |
a4198cdf0 Staging: most: ad... |
40 41 42 43 44 45 46 47 48 49 50 51 52 |
/* DRCI Addresses */ #define DRCI_REG_NI_STATE 0x0100 #define DRCI_REG_PACKET_BW 0x0101 #define DRCI_REG_NODE_ADDR 0x0102 #define DRCI_REG_NODE_POS 0x0103 #define DRCI_REG_MEP_FILTER 0x0140 #define DRCI_REG_HASH_TBL0 0x0141 #define DRCI_REG_HASH_TBL1 0x0142 #define DRCI_REG_HASH_TBL2 0x0143 #define DRCI_REG_HASH_TBL3 0x0144 #define DRCI_REG_HW_ADDR_HI 0x0145 #define DRCI_REG_HW_ADDR_MI 0x0146 #define DRCI_REG_HW_ADDR_LO 0x0147 |
d747e8ec1 staging: most: fi... |
53 54 |
#define DRCI_REG_BASE 0x1100 #define DRCI_COMMAND 0x02 |
a4198cdf0 Staging: most: ad... |
55 56 57 58 |
#define DRCI_READ_REQ 0xA0 #define DRCI_WRITE_REQ 0xA1 /** |
a4198cdf0 Staging: most: ad... |
59 60 61 |
* struct most_dci_obj - Direct Communication Interface * @kobj:position in sysfs * @usb_device: pointer to the usb device |
c0554645a staging: most: hd... |
62 |
* @reg_addr: register address for arbitrary DCI access |
a4198cdf0 Staging: most: ad... |
63 64 |
*/ struct most_dci_obj { |
4d5f022f3 staging: most: re... |
65 |
struct device dev; |
a4198cdf0 Staging: most: ad... |
66 |
struct usb_device *usb_device; |
c0554645a staging: most: hd... |
67 |
u16 reg_addr; |
a4198cdf0 Staging: most: ad... |
68 |
}; |
9cbe5aa65 staging: most: us... |
69 |
|
4d5f022f3 staging: most: re... |
70 |
#define to_dci_obj(p) container_of(p, struct most_dci_obj, dev) |
a4198cdf0 Staging: most: ad... |
71 |
|
cc28983c3 staging: most: hd... |
72 73 74 75 76 77 78 79 80 81 |
struct most_dev; struct clear_hold_work { struct work_struct ws; struct most_dev *mdev; unsigned int channel; int pipe; }; #define to_clear_hold_work(w) container_of(w, struct clear_hold_work, ws) |
a4198cdf0 Staging: most: ad... |
82 83 |
/** * struct most_dev - holds all usb interface specific stuff |
a4198cdf0 Staging: most: ad... |
84 85 86 87 88 |
* @usb_device: pointer to usb device * @iface: hardware interface * @cap: channel capabilities * @conf: channel configuration * @dci: direct communication interface of hardware |
a4198cdf0 Staging: most: ad... |
89 |
* @ep_address: endpoint address table |
a4198cdf0 Staging: most: ad... |
90 91 |
* @description: device description * @suffix: suffix for channel name |
88d1878bc staging: most: hd... |
92 |
* @channel_lock: synchronize channel access |
a4198cdf0 Staging: most: ad... |
93 94 |
* @padding_active: indicates channel uses padding * @is_channel_healthy: health status table of each channel |
27e6245e3 staging: most: hd... |
95 |
* @busy_urbs: list of anchored items |
a4198cdf0 Staging: most: ad... |
96 97 98 99 100 |
* @io_mutex: synchronize I/O with disconnect * @link_stat_timer: timer for link status reports * @poll_work_obj: work for polling link status */ struct most_dev { |
723de0f91 staging: most: re... |
101 |
struct device dev; |
a4198cdf0 Staging: most: ad... |
102 103 104 105 106 |
struct usb_device *usb_device; struct most_interface iface; struct most_channel_capability *cap; struct most_channel_config *conf; struct most_dci_obj *dci; |
a4198cdf0 Staging: most: ad... |
107 |
u8 *ep_address; |
a4198cdf0 Staging: most: ad... |
108 109 |
char description[MAX_STRING_LEN]; char suffix[MAX_NUM_ENDPOINTS][MAX_SUFFIX_LEN]; |
88d1878bc staging: most: hd... |
110 |
spinlock_t channel_lock[MAX_NUM_ENDPOINTS]; /* sync channel access */ |
a4198cdf0 Staging: most: ad... |
111 112 |
bool padding_active[MAX_NUM_ENDPOINTS]; bool is_channel_healthy[MAX_NUM_ENDPOINTS]; |
cc28983c3 staging: most: hd... |
113 |
struct clear_hold_work clear_work[MAX_NUM_ENDPOINTS]; |
27e6245e3 staging: most: hd... |
114 |
struct usb_anchor *busy_urbs; |
a4198cdf0 Staging: most: ad... |
115 116 117 |
struct mutex io_mutex; struct timer_list link_stat_timer; struct work_struct poll_work_obj; |
9917b209f staging: most: Fi... |
118 119 |
void (*on_netinfo)(struct most_interface *most_iface, unsigned char link_state, unsigned char *addrs); |
a4198cdf0 Staging: most: ad... |
120 |
}; |
9cbe5aa65 staging: most: us... |
121 |
|
a4198cdf0 Staging: most: ad... |
122 |
#define to_mdev(d) container_of(d, struct most_dev, iface) |
723de0f91 staging: most: re... |
123 |
#define to_mdev_from_dev(d) container_of(d, struct most_dev, dev) |
a4198cdf0 Staging: most: ad... |
124 |
#define to_mdev_from_work(w) container_of(w, struct most_dev, poll_work_obj) |
a4198cdf0 Staging: most: ad... |
125 126 127 128 |
static void wq_clear_halt(struct work_struct *wq_obj); static void wq_netinfo(struct work_struct *wq_obj); /** |
a4198cdf0 Staging: most: ad... |
129 130 131 132 133 134 135 |
* drci_rd_reg - read a DCI register * @dev: usb device * @reg: register address * @buf: buffer to store data * * This is reads data from INIC's direct register communication interface */ |
263702288 staging: most: pr... |
136 |
static inline int drci_rd_reg(struct usb_device *dev, u16 reg, u16 *buf) |
a4198cdf0 Staging: most: ad... |
137 |
{ |
263702288 staging: most: pr... |
138 |
int retval; |
a0dbe1b24 staging: most: us... |
139 |
__le16 *dma_buf; |
263702288 staging: most: pr... |
140 |
u8 req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; |
a0dbe1b24 staging: most: us... |
141 |
dma_buf = kzalloc(sizeof(*dma_buf), GFP_KERNEL); |
263702288 staging: most: pr... |
142 143 144 145 146 147 |
if (!dma_buf) return -ENOMEM; retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), DRCI_READ_REQ, req_type, 0x0000, |
5a10380bf staging: most: hd... |
148 |
reg, dma_buf, sizeof(*dma_buf), 5 * HZ); |
c81c9c3e0 staging: most: co... |
149 |
*buf = le16_to_cpu(*dma_buf); |
263702288 staging: most: pr... |
150 |
kfree(dma_buf); |
ffd069ec0 staging: most: us... |
151 152 153 |
if (retval < 0) return retval; return 0; |
a4198cdf0 Staging: most: ad... |
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
} /** * drci_wr_reg - write a DCI register * @dev: usb device * @reg: register address * @data: data to write * * This is writes data to INIC's direct register communication interface */ static inline int drci_wr_reg(struct usb_device *dev, u16 reg, u16 data) { return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), DRCI_WRITE_REQ, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, data, reg, NULL, 0, 5 * HZ); } |
e33269f60 staging: most: hd... |
176 177 178 179 |
static inline int start_sync_ep(struct usb_device *usb_dev, u16 ep) { return drci_wr_reg(usb_dev, DRCI_REG_BASE + DRCI_COMMAND + ep * 16, 1); } |
a4198cdf0 Staging: most: ad... |
180 |
/** |
a4198cdf0 Staging: most: ad... |
181 |
* get_stream_frame_size - calculate frame size of current configuration |
1c538a417 staging: most: us... |
182 |
* @dev: device structure |
a4198cdf0 Staging: most: ad... |
183 184 |
* @cfg: channel configuration */ |
1c538a417 staging: most: us... |
185 186 |
static unsigned int get_stream_frame_size(struct device *dev, struct most_channel_config *cfg) |
a4198cdf0 Staging: most: ad... |
187 |
{ |
2c069b61a staging: most: us... |
188 |
unsigned int frame_size; |
a4198cdf0 Staging: most: ad... |
189 190 191 |
unsigned int sub_size = cfg->subbuffer_size; if (!sub_size) { |
625732212 staging: most: us... |
192 193 |
dev_warn(dev, "Misconfig: Subbuffer size zero. "); |
2c069b61a staging: most: us... |
194 |
return 0; |
a4198cdf0 Staging: most: ad... |
195 196 |
} switch (cfg->data_type) { |
0540609fe staging: most: re... |
197 |
case MOST_CH_ISOC: |
a4198cdf0 Staging: most: ad... |
198 199 200 201 |
frame_size = AV_PACKETS_PER_XACT * sub_size; break; case MOST_CH_SYNC: if (cfg->packets_per_xact == 0) { |
625732212 staging: most: us... |
202 203 |
dev_warn(dev, "Misconfig: Packets per XACT zero "); |
a4198cdf0 Staging: most: ad... |
204 |
frame_size = 0; |
9deba73de staging: most: us... |
205 |
} else if (cfg->packets_per_xact == 0xFF) { |
a4198cdf0 Staging: most: ad... |
206 |
frame_size = (USB_MTU / sub_size) * sub_size; |
9deba73de staging: most: us... |
207 |
} else { |
a4198cdf0 Staging: most: ad... |
208 |
frame_size = cfg->packets_per_xact * sub_size; |
9deba73de staging: most: us... |
209 |
} |
a4198cdf0 Staging: most: ad... |
210 211 |
break; default: |
625732212 staging: most: us... |
212 213 |
dev_warn(dev, "Query frame size of non-streaming channel "); |
11974ace2 staging: most: us... |
214 |
frame_size = 0; |
a4198cdf0 Staging: most: ad... |
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
break; } return frame_size; } /** * hdm_poison_channel - mark buffers of this channel as invalid * @iface: pointer to the interface * @channel: channel ID * * This unlinks all URBs submitted to the HCD, * calls the associated completion function of the core and removes * them from the list. * * Returns 0 on success or error code otherwise. */ |
23fe15fad Staging: most: hd... |
231 |
static int hdm_poison_channel(struct most_interface *iface, int channel) |
a4198cdf0 Staging: most: ad... |
232 |
{ |
089612f18 staging: most: hd... |
233 |
struct most_dev *mdev = to_mdev(iface); |
b24c9fe9f staging: most: hd... |
234 235 |
unsigned long flags; spinlock_t *lock; /* temp. lock */ |
a4198cdf0 Staging: most: ad... |
236 |
|
188d5b41f staging: most: us... |
237 |
if (channel < 0 || channel >= iface->num_channels) { |
59ed0480b Staging: most: re... |
238 239 |
dev_warn(&mdev->usb_device->dev, "Channel ID out of range. "); |
a4198cdf0 Staging: most: ad... |
240 241 |
return -ECHRNG; } |
88d1878bc staging: most: hd... |
242 |
lock = mdev->channel_lock + channel; |
b24c9fe9f staging: most: hd... |
243 |
spin_lock_irqsave(lock, flags); |
a4198cdf0 Staging: most: ad... |
244 |
mdev->is_channel_healthy[channel] = false; |
b24c9fe9f staging: most: hd... |
245 |
spin_unlock_irqrestore(lock, flags); |
a4198cdf0 Staging: most: ad... |
246 |
|
cc28983c3 staging: most: hd... |
247 |
cancel_work_sync(&mdev->clear_work[channel].ws); |
a4198cdf0 Staging: most: ad... |
248 |
mutex_lock(&mdev->io_mutex); |
3a542007f staging: most: hd... |
249 |
usb_kill_anchored_urbs(&mdev->busy_urbs[channel]); |
ec58d2a87 staging: most: st... |
250 |
if (mdev->padding_active[channel]) |
a4198cdf0 Staging: most: ad... |
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
mdev->padding_active[channel] = false; if (mdev->conf[channel].data_type == MOST_CH_ASYNC) { del_timer_sync(&mdev->link_stat_timer); cancel_work_sync(&mdev->poll_work_obj); } mutex_unlock(&mdev->io_mutex); return 0; } /** * hdm_add_padding - add padding bytes * @mdev: most device * @channel: channel ID * @mbo: buffer object * * This inserts the INIC hardware specific padding bytes into a streaming * channel's buffer */ |
23fe15fad Staging: most: hd... |
270 |
static int hdm_add_padding(struct most_dev *mdev, int channel, struct mbo *mbo) |
a4198cdf0 Staging: most: ad... |
271 272 |
{ struct most_channel_config *conf = &mdev->conf[channel]; |
1c538a417 staging: most: us... |
273 |
unsigned int frame_size = get_stream_frame_size(&mdev->dev, conf); |
ac33fbb86 staging: most: hd... |
274 |
unsigned int j, num_frames; |
a4198cdf0 Staging: most: ad... |
275 |
|
a4198cdf0 Staging: most: ad... |
276 |
if (!frame_size) |
441be56f8 staging: most: us... |
277 |
return -EINVAL; |
a4198cdf0 Staging: most: ad... |
278 279 280 |
num_frames = mbo->buffer_length / frame_size; if (num_frames < 1) { |
59ed0480b Staging: most: re... |
281 282 283 |
dev_err(&mdev->usb_device->dev, "Missed minimal transfer unit. "); |
441be56f8 staging: most: us... |
284 |
return -EINVAL; |
a4198cdf0 Staging: most: ad... |
285 |
} |
5c13155d1 staging: most: us... |
286 287 288 |
for (j = num_frames - 1; j > 0; j--) memmove(mbo->virt_address + j * USB_MTU, mbo->virt_address + j * frame_size, |
a4198cdf0 Staging: most: ad... |
289 |
frame_size); |
a4198cdf0 Staging: most: ad... |
290 291 292 293 294 295 296 297 298 299 300 301 302 |
mbo->buffer_length = num_frames * USB_MTU; return 0; } /** * hdm_remove_padding - remove padding bytes * @mdev: most device * @channel: channel ID * @mbo: buffer object * * This takes the INIC hardware specific padding bytes off a streaming * channel's buffer. */ |
ba170ee2b staging: most: ma... |
303 304 |
static int hdm_remove_padding(struct most_dev *mdev, int channel, struct mbo *mbo) |
a4198cdf0 Staging: most: ad... |
305 |
{ |
a4198cdf0 Staging: most: ad... |
306 |
struct most_channel_config *const conf = &mdev->conf[channel]; |
1c538a417 staging: most: us... |
307 |
unsigned int frame_size = get_stream_frame_size(&mdev->dev, conf); |
ac33fbb86 staging: most: hd... |
308 |
unsigned int j, num_frames; |
a4198cdf0 Staging: most: ad... |
309 |
|
a4198cdf0 Staging: most: ad... |
310 |
if (!frame_size) |
441be56f8 staging: most: us... |
311 |
return -EINVAL; |
a4198cdf0 Staging: most: ad... |
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 |
num_frames = mbo->processed_length / USB_MTU; for (j = 1; j < num_frames; j++) memmove(mbo->virt_address + frame_size * j, mbo->virt_address + USB_MTU * j, frame_size); mbo->processed_length = frame_size * num_frames; return 0; } /** * hdm_write_completion - completion function for submitted Tx URBs * @urb: the URB that has been completed * * This checks the status of the completed URB. In case the URB has been * unlinked before, it is immediately freed. On any other error the MBO * transfer flag is set. On success it frees allocated resources and calls * the completion function. * * Context: interrupt! */ static void hdm_write_completion(struct urb *urb) { |
089612f18 staging: most: hd... |
336 |
struct mbo *mbo = urb->context; |
089612f18 staging: most: hd... |
337 338 |
struct most_dev *mdev = to_mdev(mbo->ifp); unsigned int channel = mbo->hdm_channel_id; |
88d1878bc staging: most: hd... |
339 |
spinlock_t *lock = mdev->channel_lock + channel; |
a4198cdf0 Staging: most: ad... |
340 |
unsigned long flags; |
a4198cdf0 Staging: most: ad... |
341 |
|
b24c9fe9f staging: most: hd... |
342 |
spin_lock_irqsave(lock, flags); |
a4198cdf0 Staging: most: ad... |
343 |
|
3a542007f staging: most: hd... |
344 345 346 |
mbo->processed_length = 0; mbo->status = MBO_E_INVAL; if (likely(mdev->is_channel_healthy[channel])) { |
a4198cdf0 Staging: most: ad... |
347 |
switch (urb->status) { |
3a542007f staging: most: hd... |
348 349 350 351 352 |
case 0: case -ESHUTDOWN: mbo->processed_length = urb->actual_length; mbo->status = MBO_SUCCESS; break; |
a4198cdf0 Staging: most: ad... |
353 |
case -EPIPE: |
be8a8ca34 staging: most: us... |
354 355 356 |
dev_warn(&mdev->usb_device->dev, "Broken pipe on ep%02x ", |
3b1a774bf staging: most: us... |
357 |
mdev->ep_address[channel]); |
879c93fef staging: most: hd... |
358 |
mdev->is_channel_healthy[channel] = false; |
cc28983c3 staging: most: hd... |
359 360 |
mdev->clear_work[channel].pipe = urb->pipe; schedule_work(&mdev->clear_work[channel].ws); |
3a542007f staging: most: hd... |
361 |
break; |
a4198cdf0 Staging: most: ad... |
362 363 364 365 |
case -ENODEV: case -EPROTO: mbo->status = MBO_E_CLOSE; break; |
a4198cdf0 Staging: most: ad... |
366 |
} |
a4198cdf0 Staging: most: ad... |
367 |
} |
cf6a599ef staging: most: hd... |
368 |
spin_unlock_irqrestore(lock, flags); |
a4198cdf0 Staging: most: ad... |
369 370 371 372 373 374 375 |
if (likely(mbo->complete)) mbo->complete(mbo); usb_free_urb(urb); } /** |
9f17591fa Staging: most: Fi... |
376 |
* hdm_read_completion - completion function for submitted Rx URBs |
a4198cdf0 Staging: most: ad... |
377 378 379 380 381 382 383 384 |
* @urb: the URB that has been completed * * This checks the status of the completed URB. In case the URB has been * unlinked before it is immediately freed. On any other error the MBO transfer * flag is set. On success it frees allocated resources, removes * padding bytes -if necessary- and calls the completion function. * * Context: interrupt! |
a4198cdf0 Staging: most: ad... |
385 386 387 |
*/ static void hdm_read_completion(struct urb *urb) { |
089612f18 staging: most: hd... |
388 |
struct mbo *mbo = urb->context; |
089612f18 staging: most: hd... |
389 390 391 |
struct most_dev *mdev = to_mdev(mbo->ifp); unsigned int channel = mbo->hdm_channel_id; struct device *dev = &mdev->usb_device->dev; |
88d1878bc staging: most: hd... |
392 |
spinlock_t *lock = mdev->channel_lock + channel; |
a4198cdf0 Staging: most: ad... |
393 |
unsigned long flags; |
a4198cdf0 Staging: most: ad... |
394 |
|
b24c9fe9f staging: most: hd... |
395 |
spin_lock_irqsave(lock, flags); |
a4198cdf0 Staging: most: ad... |
396 |
|
3a542007f staging: most: hd... |
397 398 399 |
mbo->processed_length = 0; mbo->status = MBO_E_INVAL; if (likely(mdev->is_channel_healthy[channel])) { |
a4198cdf0 Staging: most: ad... |
400 |
switch (urb->status) { |
3a542007f staging: most: hd... |
401 402 403 404 405 406 407 408 409 410 |
case 0: case -ESHUTDOWN: mbo->processed_length = urb->actual_length; mbo->status = MBO_SUCCESS; if (mdev->padding_active[channel] && hdm_remove_padding(mdev, channel, mbo)) { mbo->processed_length = 0; mbo->status = MBO_E_INVAL; } break; |
a4198cdf0 Staging: most: ad... |
411 |
case -EPIPE: |
3b1a774bf staging: most: us... |
412 413 414 |
dev_warn(dev, "Broken pipe on ep%02x ", mdev->ep_address[channel]); |
879c93fef staging: most: hd... |
415 |
mdev->is_channel_healthy[channel] = false; |
cc28983c3 staging: most: hd... |
416 417 |
mdev->clear_work[channel].pipe = urb->pipe; schedule_work(&mdev->clear_work[channel].ws); |
3a542007f staging: most: hd... |
418 |
break; |
a4198cdf0 Staging: most: ad... |
419 420 421 422 423 |
case -ENODEV: case -EPROTO: mbo->status = MBO_E_CLOSE; break; case -EOVERFLOW: |
3b1a774bf staging: most: us... |
424 425 426 |
dev_warn(dev, "Babble on ep%02x ", mdev->ep_address[channel]); |
a4198cdf0 Staging: most: ad... |
427 428 |
break; } |
a4198cdf0 Staging: most: ad... |
429 |
} |
b24c9fe9f staging: most: hd... |
430 |
|
cf6a599ef staging: most: hd... |
431 |
spin_unlock_irqrestore(lock, flags); |
a4198cdf0 Staging: most: ad... |
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
if (likely(mbo->complete)) mbo->complete(mbo); usb_free_urb(urb); } /** * hdm_enqueue - receive a buffer to be used for data transfer * @iface: interface to enqueue to * @channel: ID of the channel * @mbo: pointer to the buffer object * * This allocates a new URB and fills it according to the channel * that is being used for transmission of data. Before the URB is * submitted it is stored in the private anchor list. * * Returns 0 on success. On any error the URB is freed and a error code * is returned. * * Context: Could in _some_ cases be interrupt! */ |
ba170ee2b staging: most: ma... |
453 454 |
static int hdm_enqueue(struct most_interface *iface, int channel, struct mbo *mbo) |
a4198cdf0 Staging: most: ad... |
455 |
{ |
e3881eb53 staging: most: us... |
456 |
struct most_dev *mdev = to_mdev(iface); |
a4198cdf0 Staging: most: ad... |
457 458 459 |
struct most_channel_config *conf; int retval = 0; struct urb *urb; |
a4198cdf0 Staging: most: ad... |
460 461 |
unsigned long length; void *virt_address; |
188d5b41f staging: most: us... |
462 |
if (!mbo) |
441be56f8 staging: most: us... |
463 |
return -EINVAL; |
188d5b41f staging: most: us... |
464 |
if (iface->num_channels <= channel || channel < 0) |
a4198cdf0 Staging: most: ad... |
465 |
return -ECHRNG; |
a4198cdf0 Staging: most: ad... |
466 |
|
8bf56cfaf staging: most: us... |
467 468 469 |
urb = usb_alloc_urb(NO_ISOCHRONOUS_URB, GFP_KERNEL); if (!urb) return -ENOMEM; |
a4198cdf0 Staging: most: ad... |
470 |
conf = &mdev->conf[channel]; |
c06b99e00 staging: most: us... |
471 472 473 |
mutex_lock(&mdev->io_mutex); if (!mdev->usb_device) { retval = -ENODEV; |
8bf56cfaf staging: most: us... |
474 |
goto err_free_urb; |
c06b99e00 staging: most: us... |
475 |
} |
a4198cdf0 Staging: most: ad... |
476 |
|
dd53ecbac staging: most: hd... |
477 478 |
if ((conf->direction & MOST_CH_TX) && mdev->padding_active[channel] && hdm_add_padding(mdev, channel, mbo)) { |
441be56f8 staging: most: us... |
479 |
retval = -EINVAL; |
bddd3c254 staging: most: fi... |
480 |
goto err_free_urb; |
dd53ecbac staging: most: hd... |
481 |
} |
a4198cdf0 Staging: most: ad... |
482 483 484 485 486 487 488 489 490 491 492 493 494 |
urb->transfer_dma = mbo->bus_address; virt_address = mbo->virt_address; length = mbo->buffer_length; if (conf->direction & MOST_CH_TX) { usb_fill_bulk_urb(urb, mdev->usb_device, usb_sndbulkpipe(mdev->usb_device, mdev->ep_address[channel]), virt_address, length, hdm_write_completion, mbo); |
9a32315b0 staging: most: us... |
495 496 |
if (conf->data_type != MOST_CH_ISOC && conf->data_type != MOST_CH_SYNC) |
a4198cdf0 Staging: most: ad... |
497 498 499 500 501 502 |
urb->transfer_flags |= URB_ZERO_PACKET; } else { usb_fill_bulk_urb(urb, mdev->usb_device, usb_rcvbulkpipe(mdev->usb_device, mdev->ep_address[channel]), virt_address, |
9161e9311 staging: most: fi... |
503 |
length + conf->extra_len, |
a4198cdf0 Staging: most: ad... |
504 505 506 507 |
hdm_read_completion, mbo); } urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
27e6245e3 staging: most: hd... |
508 |
usb_anchor_urb(urb, &mdev->busy_urbs[channel]); |
ec7e0a189 staging: most: hd... |
509 |
|
a4198cdf0 Staging: most: ad... |
510 511 |
retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { |
be8a8ca34 staging: most: us... |
512 513 514 |
dev_err(&mdev->usb_device->dev, "URB submit failed with error %d. ", retval); |
bddd3c254 staging: most: fi... |
515 |
goto err_unanchor_urb; |
a4198cdf0 Staging: most: ad... |
516 |
} |
6405fe214 staging: most: us... |
517 518 |
mutex_unlock(&mdev->io_mutex); return 0; |
a4198cdf0 Staging: most: ad... |
519 |
|
bddd3c254 staging: most: fi... |
520 |
err_unanchor_urb: |
27e6245e3 staging: most: hd... |
521 |
usb_unanchor_urb(urb); |
bddd3c254 staging: most: fi... |
522 |
err_free_urb: |
a4198cdf0 Staging: most: ad... |
523 |
usb_free_urb(urb); |
c06b99e00 staging: most: us... |
524 |
mutex_unlock(&mdev->io_mutex); |
a4198cdf0 Staging: most: ad... |
525 526 |
return retval; } |
3598cec58 staging: most: ma... |
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
static void *hdm_dma_alloc(struct mbo *mbo, u32 size) { struct most_dev *mdev = to_mdev(mbo->ifp); return usb_alloc_coherent(mdev->usb_device, size, GFP_KERNEL, &mbo->bus_address); } static void hdm_dma_free(struct mbo *mbo, u32 size) { struct most_dev *mdev = to_mdev(mbo->ifp); usb_free_coherent(mdev->usb_device, size, mbo->virt_address, mbo->bus_address); } |
a4198cdf0 Staging: most: ad... |
542 543 544 545 546 |
/** * hdm_configure_channel - receive channel configuration from core * @iface: interface * @channel: channel ID * @conf: structure that holds the configuration information |
25e3854c8 staging: most: hd... |
547 548 549 550 551 552 553 554 555 |
* * The attached network interface controller (NIC) supports a padding mode * to avoid short packets on USB, hence increasing the performance due to a * lower interrupt load. This mode is default for synchronous data and can * be switched on for isochronous data. In case padding is active the * driver needs to know the frame size of the payload in order to calculate * the number of bytes it needs to pad when transmitting or to cut off when * receiving data. * |
a4198cdf0 Staging: most: ad... |
556 |
*/ |
23fe15fad Staging: most: hd... |
557 558 |
static int hdm_configure_channel(struct most_interface *iface, int channel, struct most_channel_config *conf) |
a4198cdf0 Staging: most: ad... |
559 560 561 |
{ unsigned int num_frames; unsigned int frame_size; |
089612f18 staging: most: hd... |
562 563 |
struct most_dev *mdev = to_mdev(iface); struct device *dev = &mdev->usb_device->dev; |
59ed0480b Staging: most: re... |
564 |
|
188d5b41f staging: most: us... |
565 |
if (!conf) { |
3e8621aba staging: most: us... |
566 567 |
dev_err(dev, "Bad config pointer. "); |
a4198cdf0 Staging: most: ad... |
568 569 |
return -EINVAL; } |
188d5b41f staging: most: us... |
570 |
if (channel < 0 || channel >= iface->num_channels) { |
59ed0480b Staging: most: re... |
571 572 |
dev_err(dev, "Channel ID out of range. "); |
a4198cdf0 Staging: most: ad... |
573 574 |
return -EINVAL; } |
d92e69916 staging: most: us... |
575 576 577 578 579 |
mdev->is_channel_healthy[channel] = true; mdev->clear_work[channel].channel = channel; mdev->clear_work[channel].mdev = mdev; INIT_WORK(&mdev->clear_work[channel].ws, wq_clear_halt); |
dd53ecbac staging: most: hd... |
580 |
if (!conf->num_buffers || !conf->buffer_size) { |
59ed0480b Staging: most: re... |
581 582 |
dev_err(dev, "Misconfig: buffer size or #buffers zero. "); |
a4198cdf0 Staging: most: ad... |
583 584 |
return -EINVAL; } |
dd53ecbac staging: most: hd... |
585 |
if (conf->data_type != MOST_CH_SYNC && |
0540609fe staging: most: re... |
586 |
!(conf->data_type == MOST_CH_ISOC && |
dd53ecbac staging: most: hd... |
587 |
conf->packets_per_xact != 0xFF)) { |
a4198cdf0 Staging: most: ad... |
588 |
mdev->padding_active[channel] = false; |
25e3854c8 staging: most: hd... |
589 590 591 592 593 |
/* * Since the NIC's padding mode is not going to be * used, we can skip the frame size calculations and * move directly on to exit. */ |
a4198cdf0 Staging: most: ad... |
594 595 596 597 |
goto exit; } mdev->padding_active[channel] = true; |
a4198cdf0 Staging: most: ad... |
598 |
|
1c538a417 staging: most: us... |
599 |
frame_size = get_stream_frame_size(&mdev->dev, conf); |
dd53ecbac staging: most: hd... |
600 |
if (frame_size == 0 || frame_size > USB_MTU) { |
59ed0480b Staging: most: re... |
601 602 |
dev_warn(dev, "Misconfig: frame size wrong "); |
a4198cdf0 Staging: most: ad... |
603 604 |
return -EINVAL; } |
f50019289 staging: most: us... |
605 |
num_frames = conf->buffer_size / frame_size; |
a4198cdf0 Staging: most: ad... |
606 |
if (conf->buffer_size % frame_size) { |
f50019289 staging: most: us... |
607 |
u16 old_size = conf->buffer_size; |
a4198cdf0 Staging: most: ad... |
608 |
|
f50019289 staging: most: us... |
609 610 611 612 613 |
conf->buffer_size = num_frames * frame_size; dev_warn(dev, "%s: fixed buffer size (%d -> %d) ", mdev->suffix[channel], old_size, conf->buffer_size); } |
a4198cdf0 Staging: most: ad... |
614 615 |
/* calculate extra length to comply w/ HW padding */ |
f50019289 staging: most: us... |
616 |
conf->extra_len = num_frames * (USB_MTU - frame_size); |
a4198cdf0 Staging: most: ad... |
617 618 |
exit: mdev->conf[channel] = *conf; |
7c23baa90 staging: most: hd... |
619 620 |
if (conf->data_type == MOST_CH_ASYNC) { u16 ep = mdev->ep_address[channel]; |
7c23baa90 staging: most: hd... |
621 |
|
e33269f60 staging: most: hd... |
622 |
if (start_sync_ep(mdev->usb_device, ep) < 0) |
7c23baa90 staging: most: hd... |
623 624 |
dev_warn(dev, "sync for ep%02x failed", ep); } |
a4198cdf0 Staging: most: ad... |
625 626 627 628 |
return 0; } /** |
a4198cdf0 Staging: most: ad... |
629 630 631 632 633 634 635 636 |
* hdm_request_netinfo - request network information * @iface: pointer to interface * @channel: channel ID * * This is used as trigger to set up the link status timer that * polls for the NI state of the INIC every 2 seconds. * */ |
d35bbfaa4 staging: most: re... |
637 638 639 640 |
static void hdm_request_netinfo(struct most_interface *iface, int channel, void (*on_netinfo)(struct most_interface *, unsigned char, unsigned char *)) |
a4198cdf0 Staging: most: ad... |
641 |
{ |
e3881eb53 staging: most: us... |
642 |
struct most_dev *mdev = to_mdev(iface); |
a4198cdf0 Staging: most: ad... |
643 |
|
d35bbfaa4 staging: most: re... |
644 645 646 |
mdev->on_netinfo = on_netinfo; if (!on_netinfo) return; |
a4198cdf0 Staging: most: ad... |
647 648 649 650 651 |
mdev->link_stat_timer.expires = jiffies + HZ; mod_timer(&mdev->link_stat_timer, mdev->link_stat_timer.expires); } /** |
f28e6cd3a staging: most: hd... |
652 |
* link_stat_timer_handler - schedule work obtaining mac address and link status |
a4198cdf0 Staging: most: ad... |
653 654 655 656 657 |
* @data: pointer to USB device instance * * The handler runs in interrupt context. That's why we need to defer the * tasks to a work queue. */ |
e99e88a9d treewide: setup_t... |
658 |
static void link_stat_timer_handler(struct timer_list *t) |
a4198cdf0 Staging: most: ad... |
659 |
{ |
e99e88a9d treewide: setup_t... |
660 |
struct most_dev *mdev = from_timer(mdev, t, link_stat_timer); |
a4198cdf0 Staging: most: ad... |
661 |
|
e3479f774 staging: most: hd... |
662 |
schedule_work(&mdev->poll_work_obj); |
a4198cdf0 Staging: most: ad... |
663 664 665 666 667 |
mdev->link_stat_timer.expires = jiffies + (2 * HZ); add_timer(&mdev->link_stat_timer); } /** |
f28e6cd3a staging: most: hd... |
668 |
* wq_netinfo - work queue function to deliver latest networking information |
a4198cdf0 Staging: most: ad... |
669 670 671 |
* @wq_obj: object that holds data for our deferred work to do * * This retrieves the network interface status of the USB INIC |
a4198cdf0 Staging: most: ad... |
672 673 674 |
*/ static void wq_netinfo(struct work_struct *wq_obj) { |
089612f18 staging: most: hd... |
675 |
struct most_dev *mdev = to_mdev_from_work(wq_obj); |
f28e6cd3a staging: most: hd... |
676 677 678 679 |
struct usb_device *usb_device = mdev->usb_device; struct device *dev = &usb_device->dev; u16 hi, mi, lo, link; u8 hw_addr[6]; |
ffd069ec0 staging: most: us... |
680 |
if (drci_rd_reg(usb_device, DRCI_REG_HW_ADDR_HI, &hi)) { |
f28e6cd3a staging: most: hd... |
681 682 683 684 |
dev_err(dev, "Vendor request 'hw_addr_hi' failed "); return; } |
a4198cdf0 Staging: most: ad... |
685 |
|
ffd069ec0 staging: most: us... |
686 |
if (drci_rd_reg(usb_device, DRCI_REG_HW_ADDR_MI, &mi)) { |
f28e6cd3a staging: most: hd... |
687 688 689 690 |
dev_err(dev, "Vendor request 'hw_addr_mid' failed "); return; } |
ffd069ec0 staging: most: us... |
691 |
if (drci_rd_reg(usb_device, DRCI_REG_HW_ADDR_LO, &lo)) { |
f28e6cd3a staging: most: hd... |
692 693 694 695 |
dev_err(dev, "Vendor request 'hw_addr_low' failed "); return; } |
a4198cdf0 Staging: most: ad... |
696 |
|
ffd069ec0 staging: most: us... |
697 |
if (drci_rd_reg(usb_device, DRCI_REG_NI_STATE, &link)) { |
f28e6cd3a staging: most: hd... |
698 699 |
dev_err(dev, "Vendor request 'link status' failed "); |
a4198cdf0 Staging: most: ad... |
700 |
return; |
f28e6cd3a staging: most: hd... |
701 702 703 704 705 706 707 708 |
} hw_addr[0] = hi >> 8; hw_addr[1] = hi; hw_addr[2] = mi >> 8; hw_addr[3] = mi; hw_addr[4] = lo >> 8; hw_addr[5] = lo; |
d35bbfaa4 staging: most: re... |
709 710 |
if (mdev->on_netinfo) mdev->on_netinfo(&mdev->iface, link, hw_addr); |
a4198cdf0 Staging: most: ad... |
711 712 713 714 715 716 717 718 719 720 |
} /** * wq_clear_halt - work queue function * @wq_obj: work_struct object to execute * * This sends a clear_halt to the given USB pipe. */ static void wq_clear_halt(struct work_struct *wq_obj) { |
cc28983c3 staging: most: hd... |
721 722 723 724 |
struct clear_hold_work *clear_work = to_clear_hold_work(wq_obj); struct most_dev *mdev = clear_work->mdev; unsigned int channel = clear_work->channel; int pipe = clear_work->pipe; |
1fd4fb8c6 staging: most: us... |
725 726 |
int snd_pipe; int peer; |
a4198cdf0 Staging: most: ad... |
727 |
|
cc28983c3 staging: most: hd... |
728 |
mutex_lock(&mdev->io_mutex); |
bf9503f11 staging: most: hd... |
729 |
most_stop_enqueue(&mdev->iface, channel); |
3a542007f staging: most: hd... |
730 |
usb_kill_anchored_urbs(&mdev->busy_urbs[channel]); |
cc28983c3 staging: most: hd... |
731 |
if (usb_clear_halt(mdev->usb_device, pipe)) |
59ed0480b Staging: most: re... |
732 733 |
dev_warn(&mdev->usb_device->dev, "Failed to reset endpoint. "); |
a4198cdf0 Staging: most: ad... |
734 |
|
8f20f2dca staging: most: us... |
735 736 737 738 739 740 741 742 743 744 |
/* If the functional Stall condition has been set on an * asynchronous rx channel, we need to clear the tx channel * too, since the hardware runs its clean-up sequence on both * channels, as they are physically one on the network. * * The USB interface that exposes the asynchronous channels * contains always two endpoints, and two only. */ if (mdev->conf[channel].data_type == MOST_CH_ASYNC && mdev->conf[channel].direction == MOST_CH_RX) { |
1fd4fb8c6 staging: most: us... |
745 746 747 748 749 750 |
if (channel == 0) peer = 1; else peer = 0; snd_pipe = usb_sndbulkpipe(mdev->usb_device, mdev->ep_address[peer]); |
8f20f2dca staging: most: us... |
751 752 |
usb_clear_halt(mdev->usb_device, snd_pipe); } |
879c93fef staging: most: hd... |
753 |
mdev->is_channel_healthy[channel] = true; |
72df4a55e staging: most: hd... |
754 |
most_resume_enqueue(&mdev->iface, channel); |
cc28983c3 staging: most: hd... |
755 |
mutex_unlock(&mdev->io_mutex); |
a4198cdf0 Staging: most: ad... |
756 757 758 759 760 761 762 763 764 765 766 767 |
} /** * hdm_usb_fops - file operation table for USB driver */ static const struct file_operations hdm_usb_fops = { .owner = THIS_MODULE, }; /** * usb_device_id - ID table for HCD device probing */ |
27acb5576 staging: most: us... |
768 |
static const struct usb_device_id usbid[] = { |
a4198cdf0 Staging: most: ad... |
769 |
{ USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_BRDG), }, |
654f7ec4b staging: most: hd... |
770 |
{ USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81118), }, |
b50762eaf staging: most: hd... |
771 |
{ USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81119), }, |
5bf9bd8d1 staging: most: hd... |
772 |
{ USB_DEVICE(USB_VENDOR_ID_SMSC, USB_DEV_ID_OS81210), }, |
a4198cdf0 Staging: most: ad... |
773 774 |
{ } /* Terminating entry */ }; |
a747b42c8 staging: most: hd... |
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 |
struct regs { const char *name; u16 reg; }; static const struct regs ro_regs[] = { { "ni_state", DRCI_REG_NI_STATE }, { "packet_bandwidth", DRCI_REG_PACKET_BW }, { "node_address", DRCI_REG_NODE_ADDR }, { "node_position", DRCI_REG_NODE_POS }, }; static const struct regs rw_regs[] = { { "mep_filter", DRCI_REG_MEP_FILTER }, { "mep_hash0", DRCI_REG_HASH_TBL0 }, { "mep_hash1", DRCI_REG_HASH_TBL1 }, { "mep_hash2", DRCI_REG_HASH_TBL2 }, { "mep_hash3", DRCI_REG_HASH_TBL3 }, { "mep_eui48_hi", DRCI_REG_HW_ADDR_HI }, { "mep_eui48_mi", DRCI_REG_HW_ADDR_MI }, { "mep_eui48_lo", DRCI_REG_HW_ADDR_LO }, }; static int get_stat_reg_addr(const struct regs *regs, int size, const char *name, u16 *reg_addr) { int i; for (i = 0; i < size; i++) { |
549d2db70 staging: most: us... |
804 |
if (sysfs_streq(name, regs[i].name)) { |
a747b42c8 staging: most: hd... |
805 806 807 808 |
*reg_addr = regs[i].reg; return 0; } } |
f470a5b01 staging: most: us... |
809 |
return -EINVAL; |
a747b42c8 staging: most: hd... |
810 811 812 813 |
} #define get_static_reg_addr(regs, name, reg_addr) \ get_stat_reg_addr(regs, ARRAY_SIZE(regs), name, reg_addr) |
3d9c54b5f staging: most: us... |
814 |
static ssize_t value_show(struct device *dev, struct device_attribute *attr, |
4d5f022f3 staging: most: re... |
815 |
char *buf) |
a4198cdf0 Staging: most: ad... |
816 |
{ |
98a3c4d7a staging: most: hd... |
817 |
const char *name = attr->attr.name; |
4d5f022f3 staging: most: re... |
818 |
struct most_dci_obj *dci_obj = to_dci_obj(dev); |
0e9b9d083 staging: most: hd... |
819 |
u16 val; |
a4198cdf0 Staging: most: ad... |
820 821 |
u16 reg_addr; int err; |
549d2db70 staging: most: us... |
822 |
if (sysfs_streq(name, "arb_address")) |
c0554645a staging: most: hd... |
823 824 |
return snprintf(buf, PAGE_SIZE, "%04x ", dci_obj->reg_addr); |
98a3c4d7a staging: most: hd... |
825 |
|
549d2db70 staging: most: us... |
826 |
if (sysfs_streq(name, "arb_value")) |
c0554645a staging: most: hd... |
827 |
reg_addr = dci_obj->reg_addr; |
98a3c4d7a staging: most: hd... |
828 829 |
else if (get_static_reg_addr(ro_regs, name, ®_addr) && get_static_reg_addr(rw_regs, name, ®_addr)) |
f470a5b01 staging: most: us... |
830 |
return -EINVAL; |
a4198cdf0 Staging: most: ad... |
831 |
|
0e9b9d083 staging: most: hd... |
832 |
err = drci_rd_reg(dci_obj->usb_device, reg_addr, &val); |
a4198cdf0 Staging: most: ad... |
833 834 |
if (err < 0) return err; |
0e9b9d083 staging: most: hd... |
835 836 |
return snprintf(buf, PAGE_SIZE, "%04x ", val); |
a4198cdf0 Staging: most: ad... |
837 |
} |
3d9c54b5f staging: most: us... |
838 |
static ssize_t value_store(struct device *dev, struct device_attribute *attr, |
a4198cdf0 Staging: most: ad... |
839 840 |
const char *buf, size_t count) { |
f1b9a8438 staging: most: re... |
841 |
u16 val; |
a4198cdf0 Staging: most: ad... |
842 |
u16 reg_addr; |
98a3c4d7a staging: most: hd... |
843 |
const char *name = attr->attr.name; |
4d5f022f3 staging: most: re... |
844 |
struct most_dci_obj *dci_obj = to_dci_obj(dev); |
e33269f60 staging: most: hd... |
845 |
struct usb_device *usb_dev = dci_obj->usb_device; |
a0dbe1b24 staging: most: us... |
846 |
int err; |
a4198cdf0 Staging: most: ad... |
847 |
|
a0dbe1b24 staging: most: us... |
848 |
err = kstrtou16(buf, 16, &val); |
c0554645a staging: most: hd... |
849 850 |
if (err) return err; |
549d2db70 staging: most: us... |
851 |
if (sysfs_streq(name, "arb_address")) { |
c0554645a staging: most: hd... |
852 853 854 |
dci_obj->reg_addr = val; return count; } |
98a3c4d7a staging: most: hd... |
855 |
|
549d2db70 staging: most: us... |
856 |
if (sysfs_streq(name, "arb_value")) |
e33269f60 staging: most: hd... |
857 |
err = drci_wr_reg(usb_dev, dci_obj->reg_addr, val); |
549d2db70 staging: most: us... |
858 |
else if (sysfs_streq(name, "sync_ep")) |
e33269f60 staging: most: hd... |
859 |
err = start_sync_ep(usb_dev, val); |
b2e8aa52e staging: most: us... |
860 |
else if (!get_static_reg_addr(rw_regs, name, ®_addr)) |
e33269f60 staging: most: hd... |
861 862 |
err = drci_wr_reg(usb_dev, reg_addr, val); else |
f470a5b01 staging: most: us... |
863 |
return -EINVAL; |
a4198cdf0 Staging: most: ad... |
864 |
|
a4198cdf0 Staging: most: ad... |
865 866 867 868 869 |
if (err < 0) return err; return count; } |
f15e3ad3e staging: most: ma... |
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 |
static DEVICE_ATTR(ni_state, 0444, value_show, NULL); static DEVICE_ATTR(packet_bandwidth, 0444, value_show, NULL); static DEVICE_ATTR(node_address, 0444, value_show, NULL); static DEVICE_ATTR(node_position, 0444, value_show, NULL); static DEVICE_ATTR(sync_ep, 0200, NULL, value_store); static DEVICE_ATTR(mep_filter, 0644, value_show, value_store); static DEVICE_ATTR(mep_hash0, 0644, value_show, value_store); static DEVICE_ATTR(mep_hash1, 0644, value_show, value_store); static DEVICE_ATTR(mep_hash2, 0644, value_show, value_store); static DEVICE_ATTR(mep_hash3, 0644, value_show, value_store); static DEVICE_ATTR(mep_eui48_hi, 0644, value_show, value_store); static DEVICE_ATTR(mep_eui48_mi, 0644, value_show, value_store); static DEVICE_ATTR(mep_eui48_lo, 0644, value_show, value_store); static DEVICE_ATTR(arb_address, 0644, value_show, value_store); static DEVICE_ATTR(arb_value, 0644, value_show, value_store); |
4d5f022f3 staging: most: re... |
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 |
static struct attribute *dci_attrs[] = { &dev_attr_ni_state.attr, &dev_attr_packet_bandwidth.attr, &dev_attr_node_address.attr, &dev_attr_node_position.attr, &dev_attr_sync_ep.attr, &dev_attr_mep_filter.attr, &dev_attr_mep_hash0.attr, &dev_attr_mep_hash1.attr, &dev_attr_mep_hash2.attr, &dev_attr_mep_hash3.attr, &dev_attr_mep_eui48_hi.attr, &dev_attr_mep_eui48_mi.attr, &dev_attr_mep_eui48_lo.attr, &dev_attr_arb_address.attr, &dev_attr_arb_value.attr, |
a4198cdf0 Staging: most: ad... |
902 903 |
NULL, }; |
dfeb9380e staging: most: us... |
904 |
ATTRIBUTE_GROUPS(dci); |
a4198cdf0 Staging: most: ad... |
905 |
|
869d3acd4 staging: most: us... |
906 907 908 |
static void release_dci(struct device *dev) { struct most_dci_obj *dci = to_dci_obj(dev); |
f1f48239c staging: most: us... |
909 |
put_device(dev->parent); |
869d3acd4 staging: most: us... |
910 911 |
kfree(dci); } |
723de0f91 staging: most: re... |
912 913 914 915 916 917 |
static void release_mdev(struct device *dev) { struct most_dev *mdev = to_mdev_from_dev(dev); kfree(mdev); } |
a4198cdf0 Staging: most: ad... |
918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 |
/** * hdm_probe - probe function of USB device driver * @interface: Interface of the attached USB device * @id: Pointer to the USB ID table. * * This allocates and initializes the device instance, adds the new * entry to the internal list, scans the USB descriptors and registers * the interface with the core. * Additionally, the DCI objects are created and the hardware is sync'd. * * Return 0 on success. In case of an error a negative number is returned. */ static int hdm_probe(struct usb_interface *interface, const struct usb_device_id *id) { |
089612f18 staging: most: hd... |
933 934 935 |
struct usb_host_interface *usb_iface_desc = interface->cur_altsetting; struct usb_device *usb_dev = interface_to_usbdev(interface); struct device *dev = &usb_dev->dev; |
a0dbe1b24 staging: most: us... |
936 |
struct most_dev *mdev; |
a4198cdf0 Staging: most: ad... |
937 938 939 |
unsigned int i; unsigned int num_endpoints; struct most_channel_capability *tmp_cap; |
a4198cdf0 Staging: most: ad... |
940 |
struct usb_endpoint_descriptor *ep_desc; |
c1a57be08 staging: most: us... |
941 |
int ret = -ENOMEM; |
a4198cdf0 Staging: most: ad... |
942 |
|
a0dbe1b24 staging: most: us... |
943 |
mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); |
a4198cdf0 Staging: most: ad... |
944 |
if (!mdev) |
c1a57be08 staging: most: us... |
945 |
return -ENOMEM; |
a4198cdf0 Staging: most: ad... |
946 947 948 |
usb_set_intfdata(interface, mdev); num_endpoints = usb_iface_desc->desc.bNumEndpoints; |
c1a57be08 staging: most: us... |
949 950 951 952 |
if (num_endpoints > MAX_NUM_ENDPOINTS) { kfree(mdev); return -EINVAL; } |
a4198cdf0 Staging: most: ad... |
953 954 |
mutex_init(&mdev->io_mutex); INIT_WORK(&mdev->poll_work_obj, wq_netinfo); |
e99e88a9d treewide: setup_t... |
955 |
timer_setup(&mdev->link_stat_timer, link_stat_timer_handler, 0); |
a4198cdf0 Staging: most: ad... |
956 957 |
mdev->usb_device = usb_dev; |
a4198cdf0 Staging: most: ad... |
958 959 960 |
mdev->link_stat_timer.expires = jiffies + (2 * HZ); mdev->iface.mod = hdm_usb_fops.owner; |
723de0f91 staging: most: re... |
961 |
mdev->iface.dev = &mdev->dev; |
69c90cf1b staging: most: so... |
962 |
mdev->iface.driver_dev = &interface->dev; |
a4198cdf0 Staging: most: ad... |
963 964 965 966 967 |
mdev->iface.interface = ITYPE_USB; mdev->iface.configure = hdm_configure_channel; mdev->iface.request_netinfo = hdm_request_netinfo; mdev->iface.enqueue = hdm_enqueue; mdev->iface.poison_channel = hdm_poison_channel; |
3598cec58 staging: most: ma... |
968 969 |
mdev->iface.dma_alloc = hdm_dma_alloc; mdev->iface.dma_free = hdm_dma_free; |
a4198cdf0 Staging: most: ad... |
970 971 972 973 |
mdev->iface.description = mdev->description; mdev->iface.num_channels = num_endpoints; snprintf(mdev->description, sizeof(mdev->description), |
5b082c2e0 staging: most: us... |
974 |
"%d-%s:%d.%d", |
a4198cdf0 Staging: most: ad... |
975 976 977 978 |
usb_dev->bus->busnum, usb_dev->devpath, usb_dev->config->desc.bConfigurationValue, usb_iface_desc->desc.bInterfaceNumber); |
723de0f91 staging: most: re... |
979 980 981 |
mdev->dev.init_name = mdev->description; mdev->dev.parent = &interface->dev; mdev->dev.release = release_mdev; |
a4198cdf0 Staging: most: ad... |
982 983 |
mdev->conf = kcalloc(num_endpoints, sizeof(*mdev->conf), GFP_KERNEL); if (!mdev->conf) |
bddd3c254 staging: most: fi... |
984 |
goto err_free_mdev; |
a4198cdf0 Staging: most: ad... |
985 986 987 |
mdev->cap = kcalloc(num_endpoints, sizeof(*mdev->cap), GFP_KERNEL); if (!mdev->cap) |
bddd3c254 staging: most: fi... |
988 |
goto err_free_conf; |
a4198cdf0 Staging: most: ad... |
989 990 |
mdev->iface.channel_vector = mdev->cap; |
a4198cdf0 Staging: most: ad... |
991 992 993 |
mdev->ep_address = kcalloc(num_endpoints, sizeof(*mdev->ep_address), GFP_KERNEL); if (!mdev->ep_address) |
bddd3c254 staging: most: fi... |
994 |
goto err_free_cap; |
a4198cdf0 Staging: most: ad... |
995 |
|
27e6245e3 staging: most: hd... |
996 997 998 |
mdev->busy_urbs = kcalloc(num_endpoints, sizeof(*mdev->busy_urbs), GFP_KERNEL); if (!mdev->busy_urbs) |
bddd3c254 staging: most: fi... |
999 |
goto err_free_ep_address; |
a4198cdf0 Staging: most: ad... |
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 |
tmp_cap = mdev->cap; for (i = 0; i < num_endpoints; i++) { ep_desc = &usb_iface_desc->endpoint[i].desc; mdev->ep_address[i] = ep_desc->bEndpointAddress; mdev->padding_active[i] = false; mdev->is_channel_healthy[i] = true; snprintf(&mdev->suffix[i][0], MAX_SUFFIX_LEN, "ep%02x", mdev->ep_address[i]); tmp_cap->name_suffix = &mdev->suffix[i][0]; tmp_cap->buffer_size_packet = MAX_BUF_SIZE; tmp_cap->buffer_size_streaming = MAX_BUF_SIZE; tmp_cap->num_buffers_packet = BUF_CHAIN_SIZE; tmp_cap->num_buffers_streaming = BUF_CHAIN_SIZE; tmp_cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC | |
0540609fe staging: most: re... |
1017 |
MOST_CH_ISOC | MOST_CH_SYNC; |
afd14cef0 Staging: most: Us... |
1018 |
if (usb_endpoint_dir_in(ep_desc)) |
a4198cdf0 Staging: most: ad... |
1019 1020 1021 1022 |
tmp_cap->direction = MOST_CH_RX; else tmp_cap->direction = MOST_CH_TX; tmp_cap++; |
27e6245e3 staging: most: hd... |
1023 |
init_usb_anchor(&mdev->busy_urbs[i]); |
88d1878bc staging: most: hd... |
1024 |
spin_lock_init(&mdev->channel_lock[i]); |
a4198cdf0 Staging: most: ad... |
1025 |
} |
3dcf93fe5 staging: most: us... |
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 |
dev_dbg(dev, "claimed gadget: Vendor=%4.4x ProdID=%4.4x Bus=%02x Device=%02x ", le16_to_cpu(usb_dev->descriptor.idVendor), le16_to_cpu(usb_dev->descriptor.idProduct), usb_dev->bus->busnum, usb_dev->devnum); dev_dbg(dev, "device path: /sys/bus/usb/devices/%d-%s:%d.%d ", usb_dev->bus->busnum, usb_dev->devpath, usb_dev->config->desc.bConfigurationValue, usb_iface_desc->desc.bInterfaceNumber); |
a4198cdf0 Staging: most: ad... |
1039 |
|
4d5f022f3 staging: most: re... |
1040 1041 |
ret = most_register_interface(&mdev->iface); if (ret) |
bddd3c254 staging: most: fi... |
1042 |
goto err_free_busy_urbs; |
a4198cdf0 Staging: most: ad... |
1043 1044 |
mutex_lock(&mdev->io_mutex); |
654f7ec4b staging: most: hd... |
1045 |
if (le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81118 || |
5bf9bd8d1 staging: most: hd... |
1046 1047 |
le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81119 || le16_to_cpu(usb_dev->descriptor.idProduct) == USB_DEV_ID_OS81210) { |
4d5f022f3 staging: most: re... |
1048 |
mdev->dci = kzalloc(sizeof(*mdev->dci), GFP_KERNEL); |
a4198cdf0 Staging: most: ad... |
1049 1050 1051 1052 |
if (!mdev->dci) { mutex_unlock(&mdev->io_mutex); most_deregister_interface(&mdev->iface); ret = -ENOMEM; |
bddd3c254 staging: most: fi... |
1053 |
goto err_free_busy_urbs; |
a4198cdf0 Staging: most: ad... |
1054 |
} |
4d5f022f3 staging: most: re... |
1055 |
mdev->dci->dev.init_name = "dci"; |
723de0f91 staging: most: re... |
1056 |
mdev->dci->dev.parent = get_device(mdev->iface.dev); |
dfeb9380e staging: most: us... |
1057 |
mdev->dci->dev.groups = dci_groups; |
869d3acd4 staging: most: us... |
1058 |
mdev->dci->dev.release = release_dci; |
4d5f022f3 staging: most: re... |
1059 1060 1061 1062 |
if (device_register(&mdev->dci->dev)) { mutex_unlock(&mdev->io_mutex); most_deregister_interface(&mdev->iface); ret = -ENOMEM; |
bddd3c254 staging: most: fi... |
1063 |
goto err_free_dci; |
4d5f022f3 staging: most: re... |
1064 |
} |
a4198cdf0 Staging: most: ad... |
1065 |
mdev->dci->usb_device = mdev->usb_device; |
a4198cdf0 Staging: most: ad... |
1066 1067 1068 |
} mutex_unlock(&mdev->io_mutex); return 0; |
bddd3c254 staging: most: fi... |
1069 |
err_free_dci: |
723de0f91 staging: most: re... |
1070 |
put_device(&mdev->dci->dev); |
bddd3c254 staging: most: fi... |
1071 |
err_free_busy_urbs: |
27e6245e3 staging: most: hd... |
1072 |
kfree(mdev->busy_urbs); |
bddd3c254 staging: most: fi... |
1073 |
err_free_ep_address: |
a4198cdf0 Staging: most: ad... |
1074 |
kfree(mdev->ep_address); |
bddd3c254 staging: most: fi... |
1075 |
err_free_cap: |
a4198cdf0 Staging: most: ad... |
1076 |
kfree(mdev->cap); |
bddd3c254 staging: most: fi... |
1077 |
err_free_conf: |
a4198cdf0 Staging: most: ad... |
1078 |
kfree(mdev->conf); |
bddd3c254 staging: most: fi... |
1079 |
err_free_mdev: |
723de0f91 staging: most: re... |
1080 |
put_device(&mdev->dev); |
a4198cdf0 Staging: most: ad... |
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 |
return ret; } /** * hdm_disconnect - disconnect function of USB device driver * @interface: Interface of the attached USB device * * This deregisters the interface with the core, removes the kernel timer * and frees resources. * * Context: hub kernel thread */ static void hdm_disconnect(struct usb_interface *interface) { |
089612f18 staging: most: hd... |
1095 |
struct most_dev *mdev = usb_get_intfdata(interface); |
a4198cdf0 Staging: most: ad... |
1096 |
|
a4198cdf0 Staging: most: ad... |
1097 1098 1099 1100 1101 1102 1103 |
mutex_lock(&mdev->io_mutex); usb_set_intfdata(interface, NULL); mdev->usb_device = NULL; mutex_unlock(&mdev->io_mutex); del_timer_sync(&mdev->link_stat_timer); cancel_work_sync(&mdev->poll_work_obj); |
fc157998b staging: most: us... |
1104 1105 |
if (mdev->dci) device_unregister(&mdev->dci->dev); |
a4198cdf0 Staging: most: ad... |
1106 |
most_deregister_interface(&mdev->iface); |
27e6245e3 staging: most: hd... |
1107 |
kfree(mdev->busy_urbs); |
a4198cdf0 Staging: most: ad... |
1108 1109 1110 |
kfree(mdev->cap); kfree(mdev->conf); kfree(mdev->ep_address); |
f1f48239c staging: most: us... |
1111 |
put_device(&mdev->dci->dev); |
723de0f91 staging: most: re... |
1112 |
put_device(&mdev->dev); |
a4198cdf0 Staging: most: ad... |
1113 |
} |
08e1b4274 staging: most: us... |
1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 |
static int hdm_suspend(struct usb_interface *interface, pm_message_t message) { struct most_dev *mdev = usb_get_intfdata(interface); int i; mutex_lock(&mdev->io_mutex); for (i = 0; i < mdev->iface.num_channels; i++) { most_stop_enqueue(&mdev->iface, i); usb_kill_anchored_urbs(&mdev->busy_urbs[i]); } mutex_unlock(&mdev->io_mutex); return 0; } static int hdm_resume(struct usb_interface *interface) { struct most_dev *mdev = usb_get_intfdata(interface); int i; mutex_lock(&mdev->io_mutex); for (i = 0; i < mdev->iface.num_channels; i++) most_resume_enqueue(&mdev->iface, i); mutex_unlock(&mdev->io_mutex); return 0; } |
a4198cdf0 Staging: most: ad... |
1139 1140 1141 1142 1143 |
static struct usb_driver hdm_usb = { .name = "hdm_usb", .id_table = usbid, .probe = hdm_probe, .disconnect = hdm_disconnect, |
08e1b4274 staging: most: us... |
1144 1145 |
.resume = hdm_resume, .suspend = hdm_suspend, |
a4198cdf0 Staging: most: ad... |
1146 |
}; |
b9d7adc45 staging: most: hd... |
1147 |
module_usb_driver(hdm_usb); |
a4198cdf0 Staging: most: ad... |
1148 1149 1150 |
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Gromm <christian.gromm@microchip.com>"); MODULE_DESCRIPTION("HDM_4_USB"); |