.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /**************************************************************** |
---|
2 | 3 | * |
---|
3 | 4 | * kaweth.c - driver for KL5KUSB101 based USB->Ethernet |
---|
.. | .. |
---|
13 | 14 | * Based off of (and with thanks to) Petko Manolov's pegaus.c driver. |
---|
14 | 15 | * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki |
---|
15 | 16 | * for providing the firmware and driver resources. |
---|
16 | | - * |
---|
17 | | - * This program is free software; you can redistribute it and/or |
---|
18 | | - * modify it under the terms of the GNU General Public License as |
---|
19 | | - * published by the Free Software Foundation; either version 2, or |
---|
20 | | - * (at your option) any later version. |
---|
21 | | - * |
---|
22 | | - * This program is distributed in the hope that it will be useful, |
---|
23 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
24 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
25 | | - * GNU General Public License for more details. |
---|
26 | | - * |
---|
27 | | - * You should have received a copy of the GNU General Public License |
---|
28 | | - * along with this program; if not, see <http://www.gnu.org/licenses/>. |
---|
29 | 17 | * |
---|
30 | 18 | ****************************************************************/ |
---|
31 | 19 | |
---|
.. | .. |
---|
115 | 103 | const struct usb_device_id *id /* from id_table */ |
---|
116 | 104 | ); |
---|
117 | 105 | static void kaweth_disconnect(struct usb_interface *intf); |
---|
118 | | -static int kaweth_internal_control_msg(struct usb_device *usb_dev, |
---|
119 | | - unsigned int pipe, |
---|
120 | | - struct usb_ctrlrequest *cmd, void *data, |
---|
121 | | - int len, int timeout); |
---|
122 | 106 | static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); |
---|
123 | 107 | static int kaweth_resume(struct usb_interface *intf); |
---|
124 | 108 | |
---|
.. | .. |
---|
248 | 232 | }; |
---|
249 | 233 | |
---|
250 | 234 | /**************************************************************** |
---|
251 | | - * kaweth_control |
---|
252 | | - ****************************************************************/ |
---|
253 | | -static int kaweth_control(struct kaweth_device *kaweth, |
---|
254 | | - unsigned int pipe, |
---|
255 | | - __u8 request, |
---|
256 | | - __u8 requesttype, |
---|
257 | | - __u16 value, |
---|
258 | | - __u16 index, |
---|
259 | | - void *data, |
---|
260 | | - __u16 size, |
---|
261 | | - int timeout) |
---|
262 | | -{ |
---|
263 | | - struct usb_ctrlrequest *dr; |
---|
264 | | - int retval; |
---|
265 | | - |
---|
266 | | - if(in_interrupt()) { |
---|
267 | | - netdev_dbg(kaweth->net, "in_interrupt()\n"); |
---|
268 | | - return -EBUSY; |
---|
269 | | - } |
---|
270 | | - |
---|
271 | | - dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); |
---|
272 | | - if (!dr) |
---|
273 | | - return -ENOMEM; |
---|
274 | | - |
---|
275 | | - dr->bRequestType = requesttype; |
---|
276 | | - dr->bRequest = request; |
---|
277 | | - dr->wValue = cpu_to_le16(value); |
---|
278 | | - dr->wIndex = cpu_to_le16(index); |
---|
279 | | - dr->wLength = cpu_to_le16(size); |
---|
280 | | - |
---|
281 | | - retval = kaweth_internal_control_msg(kaweth->dev, |
---|
282 | | - pipe, |
---|
283 | | - dr, |
---|
284 | | - data, |
---|
285 | | - size, |
---|
286 | | - timeout); |
---|
287 | | - |
---|
288 | | - kfree(dr); |
---|
289 | | - return retval; |
---|
290 | | -} |
---|
291 | | - |
---|
292 | | -/**************************************************************** |
---|
293 | 235 | * kaweth_read_configuration |
---|
294 | 236 | ****************************************************************/ |
---|
295 | 237 | static int kaweth_read_configuration(struct kaweth_device *kaweth) |
---|
296 | 238 | { |
---|
297 | | - int retval; |
---|
298 | | - |
---|
299 | | - retval = kaweth_control(kaweth, |
---|
300 | | - usb_rcvctrlpipe(kaweth->dev, 0), |
---|
| 239 | + return usb_control_msg(kaweth->dev, usb_rcvctrlpipe(kaweth->dev, 0), |
---|
301 | 240 | KAWETH_COMMAND_GET_ETHERNET_DESC, |
---|
302 | 241 | USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, |
---|
303 | | - 0, |
---|
304 | | - 0, |
---|
305 | | - (void *)&kaweth->configuration, |
---|
| 242 | + 0, 0, |
---|
| 243 | + &kaweth->configuration, |
---|
306 | 244 | sizeof(kaweth->configuration), |
---|
307 | 245 | KAWETH_CONTROL_TIMEOUT); |
---|
308 | | - |
---|
309 | | - return retval; |
---|
310 | 246 | } |
---|
311 | 247 | |
---|
312 | 248 | /**************************************************************** |
---|
.. | .. |
---|
314 | 250 | ****************************************************************/ |
---|
315 | 251 | static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) |
---|
316 | 252 | { |
---|
317 | | - int retval; |
---|
318 | | - |
---|
319 | 253 | netdev_dbg(kaweth->net, "Setting URB size to %d\n", (unsigned)urb_size); |
---|
320 | 254 | |
---|
321 | | - retval = kaweth_control(kaweth, |
---|
322 | | - usb_sndctrlpipe(kaweth->dev, 0), |
---|
323 | | - KAWETH_COMMAND_SET_URB_SIZE, |
---|
324 | | - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
325 | | - urb_size, |
---|
326 | | - 0, |
---|
327 | | - (void *)&kaweth->scratch, |
---|
328 | | - 0, |
---|
329 | | - KAWETH_CONTROL_TIMEOUT); |
---|
330 | | - |
---|
331 | | - return retval; |
---|
| 255 | + return usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
---|
| 256 | + KAWETH_COMMAND_SET_URB_SIZE, |
---|
| 257 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
| 258 | + urb_size, 0, |
---|
| 259 | + &kaweth->scratch, 0, |
---|
| 260 | + KAWETH_CONTROL_TIMEOUT); |
---|
332 | 261 | } |
---|
333 | 262 | |
---|
334 | 263 | /**************************************************************** |
---|
.. | .. |
---|
336 | 265 | ****************************************************************/ |
---|
337 | 266 | static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) |
---|
338 | 267 | { |
---|
339 | | - int retval; |
---|
340 | | - |
---|
341 | 268 | netdev_dbg(kaweth->net, "Set SOFS wait to %d\n", (unsigned)sofs_wait); |
---|
342 | 269 | |
---|
343 | | - retval = kaweth_control(kaweth, |
---|
344 | | - usb_sndctrlpipe(kaweth->dev, 0), |
---|
345 | | - KAWETH_COMMAND_SET_SOFS_WAIT, |
---|
346 | | - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
347 | | - sofs_wait, |
---|
348 | | - 0, |
---|
349 | | - (void *)&kaweth->scratch, |
---|
350 | | - 0, |
---|
351 | | - KAWETH_CONTROL_TIMEOUT); |
---|
352 | | - |
---|
353 | | - return retval; |
---|
| 270 | + return usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
---|
| 271 | + KAWETH_COMMAND_SET_SOFS_WAIT, |
---|
| 272 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
| 273 | + sofs_wait, 0, |
---|
| 274 | + &kaweth->scratch, 0, |
---|
| 275 | + KAWETH_CONTROL_TIMEOUT); |
---|
354 | 276 | } |
---|
355 | 277 | |
---|
356 | 278 | /**************************************************************** |
---|
.. | .. |
---|
359 | 281 | static int kaweth_set_receive_filter(struct kaweth_device *kaweth, |
---|
360 | 282 | __u16 receive_filter) |
---|
361 | 283 | { |
---|
362 | | - int retval; |
---|
363 | | - |
---|
364 | 284 | netdev_dbg(kaweth->net, "Set receive filter to %d\n", |
---|
365 | 285 | (unsigned)receive_filter); |
---|
366 | 286 | |
---|
367 | | - retval = kaweth_control(kaweth, |
---|
368 | | - usb_sndctrlpipe(kaweth->dev, 0), |
---|
369 | | - KAWETH_COMMAND_SET_PACKET_FILTER, |
---|
370 | | - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
371 | | - receive_filter, |
---|
372 | | - 0, |
---|
373 | | - (void *)&kaweth->scratch, |
---|
374 | | - 0, |
---|
375 | | - KAWETH_CONTROL_TIMEOUT); |
---|
376 | | - |
---|
377 | | - return retval; |
---|
| 287 | + return usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
---|
| 288 | + KAWETH_COMMAND_SET_PACKET_FILTER, |
---|
| 289 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
| 290 | + receive_filter, 0, |
---|
| 291 | + &kaweth->scratch, 0, |
---|
| 292 | + KAWETH_CONTROL_TIMEOUT); |
---|
378 | 293 | } |
---|
379 | 294 | |
---|
380 | 295 | /**************************************************************** |
---|
.. | .. |
---|
419 | 334 | kaweth->firmware_buf, kaweth); |
---|
420 | 335 | netdev_dbg(kaweth->net, "Firmware length: %d\n", data_len); |
---|
421 | 336 | |
---|
422 | | - return kaweth_control(kaweth, |
---|
423 | | - usb_sndctrlpipe(kaweth->dev, 0), |
---|
| 337 | + return usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
---|
424 | 338 | KAWETH_COMMAND_SCAN, |
---|
425 | 339 | USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
426 | | - 0, |
---|
427 | | - 0, |
---|
428 | | - (void *)kaweth->firmware_buf, |
---|
429 | | - data_len, |
---|
| 340 | + 0, 0, |
---|
| 341 | + kaweth->firmware_buf, data_len, |
---|
430 | 342 | KAWETH_CONTROL_TIMEOUT); |
---|
431 | 343 | } |
---|
432 | 344 | |
---|
.. | .. |
---|
445 | 357 | kaweth->firmware_buf[6] = 0x00; |
---|
446 | 358 | kaweth->firmware_buf[7] = 0x00; |
---|
447 | 359 | |
---|
448 | | - return kaweth_control(kaweth, |
---|
449 | | - usb_sndctrlpipe(kaweth->dev, 0), |
---|
450 | | - KAWETH_COMMAND_SCAN, |
---|
451 | | - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
452 | | - 0, |
---|
453 | | - 0, |
---|
454 | | - (void *)kaweth->firmware_buf, |
---|
455 | | - 8, |
---|
456 | | - KAWETH_CONTROL_TIMEOUT); |
---|
| 360 | + return usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
---|
| 361 | + KAWETH_COMMAND_SCAN, |
---|
| 362 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
| 363 | + 0, 0, |
---|
| 364 | + (void *)kaweth->firmware_buf, 8, |
---|
| 365 | + KAWETH_CONTROL_TIMEOUT); |
---|
457 | 366 | } |
---|
458 | 367 | |
---|
459 | 368 | /**************************************************************** |
---|
.. | .. |
---|
576 | 485 | return result; |
---|
577 | 486 | } |
---|
578 | 487 | |
---|
579 | | -static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth); |
---|
| 488 | +static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth, |
---|
| 489 | + bool may_sleep); |
---|
580 | 490 | |
---|
581 | 491 | /**************************************************************** |
---|
582 | 492 | * kaweth_usb_receive |
---|
.. | .. |
---|
706 | 616 | |
---|
707 | 617 | netif_start_queue(net); |
---|
708 | 618 | |
---|
709 | | - kaweth_async_set_rx_mode(kaweth); |
---|
| 619 | + kaweth_async_set_rx_mode(kaweth, true); |
---|
710 | 620 | return 0; |
---|
711 | 621 | |
---|
712 | 622 | err_out: |
---|
.. | .. |
---|
794 | 704 | |
---|
795 | 705 | spin_lock_irq(&kaweth->device_lock); |
---|
796 | 706 | |
---|
797 | | - kaweth_async_set_rx_mode(kaweth); |
---|
| 707 | + kaweth_async_set_rx_mode(kaweth, false); |
---|
798 | 708 | netif_stop_queue(net); |
---|
799 | 709 | if (IS_BLOCKED(kaweth->status)) { |
---|
800 | 710 | goto skip; |
---|
.. | .. |
---|
871 | 781 | /**************************************************************** |
---|
872 | 782 | * kaweth_async_set_rx_mode |
---|
873 | 783 | ****************************************************************/ |
---|
874 | | -static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) |
---|
| 784 | +static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth, |
---|
| 785 | + bool may_sleep) |
---|
875 | 786 | { |
---|
876 | | - int result; |
---|
| 787 | + int ret; |
---|
877 | 788 | __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap; |
---|
878 | 789 | |
---|
879 | 790 | kaweth->packet_filter_bitmap = 0; |
---|
880 | 791 | if (packet_filter_bitmap == 0) |
---|
881 | 792 | return; |
---|
882 | 793 | |
---|
883 | | - if (in_interrupt()) |
---|
| 794 | + if (!may_sleep) |
---|
884 | 795 | return; |
---|
885 | 796 | |
---|
886 | | - result = kaweth_control(kaweth, |
---|
887 | | - usb_sndctrlpipe(kaweth->dev, 0), |
---|
888 | | - KAWETH_COMMAND_SET_PACKET_FILTER, |
---|
889 | | - USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
890 | | - packet_filter_bitmap, |
---|
891 | | - 0, |
---|
892 | | - (void *)&kaweth->scratch, |
---|
893 | | - 0, |
---|
894 | | - KAWETH_CONTROL_TIMEOUT); |
---|
895 | | - |
---|
896 | | - if(result < 0) { |
---|
| 797 | + ret = usb_control_msg(kaweth->dev, usb_sndctrlpipe(kaweth->dev, 0), |
---|
| 798 | + KAWETH_COMMAND_SET_PACKET_FILTER, |
---|
| 799 | + USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE, |
---|
| 800 | + packet_filter_bitmap, 0, |
---|
| 801 | + &kaweth->scratch, 0, |
---|
| 802 | + KAWETH_CONTROL_TIMEOUT); |
---|
| 803 | + if (ret < 0) |
---|
897 | 804 | dev_err(&kaweth->intf->dev, "Failed to set Rx mode: %d\n", |
---|
898 | | - result); |
---|
899 | | - } |
---|
900 | | - else { |
---|
| 805 | + ret); |
---|
| 806 | + else |
---|
901 | 807 | netdev_dbg(kaweth->net, "Set Rx mode to %d\n", |
---|
902 | 808 | packet_filter_bitmap); |
---|
903 | | - } |
---|
904 | 809 | } |
---|
905 | 810 | |
---|
906 | 811 | /**************************************************************** |
---|
907 | 812 | * kaweth_tx_timeout |
---|
908 | 813 | ****************************************************************/ |
---|
909 | | -static void kaweth_tx_timeout(struct net_device *net) |
---|
| 814 | +static void kaweth_tx_timeout(struct net_device *net, unsigned int txqueue) |
---|
910 | 815 | { |
---|
911 | 816 | struct kaweth_device *kaweth = netdev_priv(net); |
---|
912 | 817 | |
---|
.. | .. |
---|
1207 | 1112 | free_netdev(netdev); |
---|
1208 | 1113 | } |
---|
1209 | 1114 | |
---|
1210 | | - |
---|
1211 | | -// FIXME this completion stuff is a modified clone of |
---|
1212 | | -// an OLD version of some stuff in usb.c ... |
---|
1213 | | -struct usb_api_data { |
---|
1214 | | - wait_queue_head_t wqh; |
---|
1215 | | - int done; |
---|
1216 | | -}; |
---|
1217 | | - |
---|
1218 | | -/*-------------------------------------------------------------------* |
---|
1219 | | - * completion handler for compatibility wrappers (sync control/bulk) * |
---|
1220 | | - *-------------------------------------------------------------------*/ |
---|
1221 | | -static void usb_api_blocking_completion(struct urb *urb) |
---|
1222 | | -{ |
---|
1223 | | - struct usb_api_data *awd = (struct usb_api_data *)urb->context; |
---|
1224 | | - |
---|
1225 | | - awd->done=1; |
---|
1226 | | - wake_up(&awd->wqh); |
---|
1227 | | -} |
---|
1228 | | - |
---|
1229 | | -/*-------------------------------------------------------------------* |
---|
1230 | | - * COMPATIBILITY STUFF * |
---|
1231 | | - *-------------------------------------------------------------------*/ |
---|
1232 | | - |
---|
1233 | | -// Starts urb and waits for completion or timeout |
---|
1234 | | -static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) |
---|
1235 | | -{ |
---|
1236 | | - struct usb_api_data awd; |
---|
1237 | | - int status; |
---|
1238 | | - |
---|
1239 | | - init_waitqueue_head(&awd.wqh); |
---|
1240 | | - awd.done = 0; |
---|
1241 | | - |
---|
1242 | | - urb->context = &awd; |
---|
1243 | | - status = usb_submit_urb(urb, GFP_ATOMIC); |
---|
1244 | | - if (status) { |
---|
1245 | | - // something went wrong |
---|
1246 | | - usb_free_urb(urb); |
---|
1247 | | - return status; |
---|
1248 | | - } |
---|
1249 | | - |
---|
1250 | | - if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { |
---|
1251 | | - // timeout |
---|
1252 | | - dev_warn(&urb->dev->dev, "usb_control/bulk_msg: timeout\n"); |
---|
1253 | | - usb_kill_urb(urb); // remove urb safely |
---|
1254 | | - status = -ETIMEDOUT; |
---|
1255 | | - } |
---|
1256 | | - else { |
---|
1257 | | - status = urb->status; |
---|
1258 | | - } |
---|
1259 | | - |
---|
1260 | | - if (actual_length) { |
---|
1261 | | - *actual_length = urb->actual_length; |
---|
1262 | | - } |
---|
1263 | | - |
---|
1264 | | - usb_free_urb(urb); |
---|
1265 | | - return status; |
---|
1266 | | -} |
---|
1267 | | - |
---|
1268 | | -/*-------------------------------------------------------------------*/ |
---|
1269 | | -// returns status (negative) or length (positive) |
---|
1270 | | -static int kaweth_internal_control_msg(struct usb_device *usb_dev, |
---|
1271 | | - unsigned int pipe, |
---|
1272 | | - struct usb_ctrlrequest *cmd, void *data, |
---|
1273 | | - int len, int timeout) |
---|
1274 | | -{ |
---|
1275 | | - struct urb *urb; |
---|
1276 | | - int retv; |
---|
1277 | | - int length = 0; /* shut up GCC */ |
---|
1278 | | - |
---|
1279 | | - urb = usb_alloc_urb(0, GFP_ATOMIC); |
---|
1280 | | - if (!urb) |
---|
1281 | | - return -ENOMEM; |
---|
1282 | | - |
---|
1283 | | - usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char*)cmd, data, |
---|
1284 | | - len, usb_api_blocking_completion, NULL); |
---|
1285 | | - |
---|
1286 | | - retv = usb_start_wait_urb(urb, timeout, &length); |
---|
1287 | | - if (retv < 0) { |
---|
1288 | | - return retv; |
---|
1289 | | - } |
---|
1290 | | - else { |
---|
1291 | | - return length; |
---|
1292 | | - } |
---|
1293 | | -} |
---|
1294 | 1115 | |
---|
1295 | 1116 | module_usb_driver(kaweth_driver); |
---|