source: mainline/uspace/lib/nic/src/nic_impl.c@ e86b8f0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e86b8f0 was 6d8455d, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Eliminate packet_t from sending direction of NIC interface.

  • Property mode set to 100644
File size: 24.7 KB
Line 
1/*
2 * Copyright (c) 2011 Radim Vansa
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @addtogroup libnic
31 * @{
32 */
33/**
34 * @file
35 * @brief Default DDF NIC interface methods implementations
36 */
37
38#include <str_error.h>
39#include <ipc/services.h>
40#include <ns.h>
41#include "nic_driver.h"
42#include "nic_impl.h"
43
44/**
45 * Default implementation of the set_state method. Trivial.
46 *
47 * @param fun
48 * @param[out] state
49 *
50 * @return EOK always.
51 */
52int nic_get_state_impl(ddf_fun_t *fun, nic_device_state_t *state)
53{
54 nic_t *nic_data = (nic_t *) fun->driver_data;
55 fibril_rwlock_read_lock(&nic_data->main_lock);
56 *state = nic_data->state;
57 fibril_rwlock_read_unlock(&nic_data->main_lock);
58 return EOK;
59}
60
61/**
62 * Default implementation of the set_state method. Changes the internal
63 * driver's state, calls the appropriate callback and notifies the NIL service
64 * about this change.
65 *
66 * @param fun
67 * @param state The new device's state
68 *
69 * @return EOK If the state was changed
70 * @return EINVAL If the state cannot be changed
71 */
72int nic_set_state_impl(ddf_fun_t *fun, nic_device_state_t state)
73{
74 if (state >= NIC_STATE_MAX) {
75 return EINVAL;
76 }
77
78 nic_t *nic_data = (nic_t *) fun->driver_data;
79
80 fibril_rwlock_write_lock(&nic_data->main_lock);
81 if (nic_data->state == state) {
82 /* No change, nothing to do */
83 fibril_rwlock_write_unlock(&nic_data->main_lock);
84 return EOK;
85 }
86 if (state == NIC_STATE_ACTIVE) {
87 if (nic_data->nil_session == NULL || nic_data->net_session == NULL
88 || nic_data->device_id < 0) {
89 fibril_rwlock_write_unlock(&nic_data->main_lock);
90 return EINVAL;
91 }
92 }
93
94 state_change_handler event_handler = NULL;
95 switch (state) {
96 case NIC_STATE_STOPPED:
97 event_handler = nic_data->on_stopping;
98 break;
99 case NIC_STATE_DOWN:
100 event_handler = nic_data->on_going_down;
101 break;
102 case NIC_STATE_ACTIVE:
103 event_handler = nic_data->on_activating;
104 break;
105 default:
106 break;
107 }
108 if (event_handler != NULL) {
109 int rc = event_handler(nic_data);
110 if (rc != EOK) {
111 fibril_rwlock_write_unlock(&nic_data->main_lock);
112 return EINVAL;
113 }
114 }
115
116 if (state == NIC_STATE_STOPPED) {
117 /* Notify upper layers that we are reseting the MAC */
118 int rc = nil_addr_changed_msg(nic_data->nil_session,
119 nic_data->device_id, &nic_data->default_mac);
120 nic_data->poll_mode = nic_data->default_poll_mode;
121 memcpy(&nic_data->poll_period, &nic_data->default_poll_period,
122 sizeof (struct timeval));
123 if (rc != EOK) {
124 /* We have already ran the on stopped handler, even if we
125 * terminated the state change we would end up in undefined state.
126 * Therefore we just log the problem. */
127 }
128
129 fibril_rwlock_write_lock(&nic_data->stats_lock);
130 bzero(&nic_data->stats, sizeof (nic_device_stats_t));
131 fibril_rwlock_write_unlock(&nic_data->stats_lock);
132
133 fibril_rwlock_write_lock(&nic_data->rxc_lock);
134 nic_rxc_clear(&nic_data->rx_control);
135 /* Reinsert device's default MAC */
136 nic_rxc_set_addr(&nic_data->rx_control, NULL,
137 &nic_data->default_mac);
138 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
139 memcpy(&nic_data->mac, &nic_data->default_mac, sizeof (nic_address_t));
140
141 fibril_rwlock_write_lock(&nic_data->wv_lock);
142 nic_wol_virtues_clear(&nic_data->wol_virtues);
143 fibril_rwlock_write_unlock(&nic_data->wv_lock);
144
145 /* Ensure stopping period of NIC_POLL_SOFTWARE_PERIODIC */
146 nic_sw_period_stop(nic_data);
147 }
148
149 nic_data->state = state;
150
151 nil_device_state_msg(nic_data->nil_session, nic_data->device_id, state);
152
153 fibril_rwlock_write_unlock(&nic_data->main_lock);
154
155 return EOK;
156}
157
158/**
159 * Default implementation of the send_frame method.
160 * Send messages to the network.
161 *
162 * @param fun
163 * @param data Frame data
164 * @param size Frame size in bytes
165 *
166 * @return EOK If the message was sent
167 * @return EBUSY If the device is not in state when the frame can be sent.
168 */
169int nic_send_frame_impl(ddf_fun_t *fun, void *data, size_t size)
170{
171 nic_t *nic_data = (nic_t *) fun->driver_data;
172
173 fibril_rwlock_read_lock(&nic_data->main_lock);
174 if (nic_data->state != NIC_STATE_ACTIVE || nic_data->tx_busy) {
175 fibril_rwlock_read_unlock(&nic_data->main_lock);
176 return EBUSY;
177 }
178
179 nic_data->send_frame(nic_data, data, size);
180 return EOK;
181}
182
183/**
184 * Default implementation of the connect_to_nil method.
185 * Connects the driver to the NIL service.
186 *
187 * @param fun
188 * @param nil_service ID of the server implementing the NIL service
189 * @param device_id ID of the device as used in higher layers
190 *
191 * @return EOK If the services were bound
192 * @return Negative error code from service_connect_blocking
193 */
194int nic_connect_to_nil_impl(ddf_fun_t *fun, services_t nil_service,
195 nic_device_id_t device_id)
196{
197 nic_t *nic_data = (nic_t *) fun->driver_data;
198 fibril_rwlock_write_lock(&nic_data->main_lock);
199
200 nic_data->device_id = device_id;
201
202 nic_data->nil_session = service_connect_blocking(EXCHANGE_SERIALIZE,
203 nil_service, 0, 0);
204 if (nic_data->nil_session != NULL) {
205 fibril_rwlock_write_unlock(&nic_data->main_lock);
206 return EOK;
207 }
208
209 fibril_rwlock_write_unlock(&nic_data->main_lock);
210 return EHANGUP;
211}
212
213/**
214 * Default implementation of the get_address method.
215 * Retrieves the NIC's physical address.
216 *
217 * @param fun
218 * @param address Pointer to the structure where the address will be stored.
219 *
220 * @return EOK If the services were bound
221 * @return ELIMIT If the buffer is too short
222 */
223int nic_get_address_impl(ddf_fun_t *fun, nic_address_t *address)
224{
225 assert(address);
226 nic_t *nic_data = (nic_t *) fun->driver_data;
227 fibril_rwlock_read_lock(&nic_data->main_lock);
228 memcpy(address, &nic_data->mac, sizeof (nic_address_t));
229 fibril_rwlock_read_unlock(&nic_data->main_lock);
230 return EOK;
231}
232
233/**
234 * Default implementation of the get_stats method. Copies the statistics from
235 * the drivers data to supplied buffer.
236 *
237 * @param fun
238 * @param[out] stats The buffer for statistics
239 *
240 * @return EOK (cannot fail)
241 */
242int nic_get_stats_impl(ddf_fun_t *fun, nic_device_stats_t *stats)
243{
244 nic_t *nic_data = (nic_t *) fun->driver_data;
245 assert (stats != NULL);
246 fibril_rwlock_read_lock(&nic_data->stats_lock);
247 memcpy(stats, &nic_data->stats, sizeof (nic_device_stats_t));
248 fibril_rwlock_read_unlock(&nic_data->stats_lock);
249 return EOK;
250}
251
252/**
253 * Default implementation of unicast_get_mode method.
254 *
255 * @param fun
256 * @param[out] mode Current operation mode
257 * @param[in] max_count Max number of addresses that can be written into the
258 * buffer (addr_list).
259 * @param[out] addr_list Buffer for addresses
260 * @param[out] addr_count Number of addresses written into the list
261 *
262 * @return EOK
263 */
264int nic_unicast_get_mode_impl(ddf_fun_t *fun, nic_unicast_mode_t *mode,
265 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
266{
267 nic_t *nic_data = (nic_t *) fun->driver_data;
268 fibril_rwlock_read_lock(&nic_data->rxc_lock);
269 nic_rxc_unicast_get_mode(&nic_data->rx_control, mode, max_count,
270 addr_list, addr_count);
271 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
272 return EOK;
273}
274
275/**
276 * Default implementation of unicast_set_mode method.
277 *
278 * @param fun
279 * @param[in] mode New operation mode
280 * @param[in] addr_list List of unicast addresses
281 * @param[in] addr_count Number of addresses in the list
282 *
283 * @return EOK
284 * @return EINVAL
285 * @return ENOTSUP
286 * @return ENOMEM
287 */
288int nic_unicast_set_mode_impl(ddf_fun_t *fun,
289 nic_unicast_mode_t mode, const nic_address_t *addr_list, size_t addr_count)
290{
291 assert((addr_count == 0 && addr_list == NULL)
292 || (addr_count != 0 && addr_list != NULL));
293 size_t i;
294 for (i = 0; i < addr_count; ++i) {
295 if (addr_list[i].address[0] & 1)
296 return EINVAL;
297 }
298
299 nic_t *nic_data = (nic_t *) fun->driver_data;
300 fibril_rwlock_write_lock(&nic_data->rxc_lock);
301 int rc = ENOTSUP;
302 if (nic_data->on_unicast_mode_change) {
303 rc = nic_data->on_unicast_mode_change(nic_data,
304 mode, addr_list, addr_count);
305 }
306 if (rc == EOK) {
307 rc = nic_rxc_unicast_set_mode(&nic_data->rx_control, mode,
308 addr_list, addr_count);
309 /* After changing the mode the addr db gets cleared, therefore we have
310 * to reinsert also the physical address of NIC.
311 */
312 nic_rxc_set_addr(&nic_data->rx_control, NULL, &nic_data->mac);
313 }
314 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
315 return rc;
316}
317
318
319/**
320 * Default implementation of multicast_get_mode method.
321 *
322 * @param fun
323 * @param[out] mode Current operation mode
324 * @param[in] max_count Max number of addresses that can be written into the
325 * buffer (addr_list).
326 * @param[out] addr_list Buffer for addresses
327 * @param[out] addr_count Number of addresses written into the list
328 *
329 * @return EOK
330 */
331int nic_multicast_get_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t *mode,
332 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
333{
334 nic_t *nic_data = (nic_t *) fun->driver_data;
335 fibril_rwlock_read_lock(&nic_data->rxc_lock);
336 nic_rxc_multicast_get_mode(&nic_data->rx_control, mode, max_count,
337 addr_list, addr_count);
338 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
339 return EOK;
340}
341
342/**
343 * Default implementation of multicast_set_mode method.
344 *
345 * @param fun
346 * @param[in] mode New operation mode
347 * @param[in] addr_list List of multicast addresses
348 * @param[in] addr_count Number of addresses in the list
349 *
350 * @return EOK
351 * @return EINVAL
352 * @return ENOTSUP
353 * @return ENOMEM
354 */
355int nic_multicast_set_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t mode,
356 const nic_address_t *addr_list, size_t addr_count)
357{
358 assert((addr_count == 0 && addr_list == NULL)
359 || (addr_count != 0 && addr_list != NULL));
360 size_t i;
361 for (i = 0; i < addr_count; ++i) {
362 if (!(addr_list[i].address[0] & 1))
363 return EINVAL;
364 }
365
366 nic_t *nic_data = (nic_t *) fun->dev->driver_data;
367 fibril_rwlock_write_lock(&nic_data->rxc_lock);
368 int rc = ENOTSUP;
369 if (nic_data->on_multicast_mode_change) {
370 rc = nic_data->on_multicast_mode_change(nic_data, mode, addr_list, addr_count);
371 }
372 if (rc == EOK) {
373 rc = nic_rxc_multicast_set_mode(&nic_data->rx_control, mode,
374 addr_list, addr_count);
375 }
376 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
377 return rc;
378}
379
380/**
381 * Default implementation of broadcast_get_mode method.
382 *
383 * @param fun
384 * @param[out] mode Current operation mode
385 *
386 * @return EOK
387 */
388int nic_broadcast_get_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t *mode)
389{
390 nic_t *nic_data = (nic_t *) fun->driver_data;
391 fibril_rwlock_read_lock(&nic_data->rxc_lock);
392 nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
393 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
394 return EOK;
395}
396
397/**
398 * Default implementation of broadcast_set_mode method.
399 *
400 * @param fun
401 * @param[in] mode New operation mode
402 *
403 * @return EOK
404 * @return EINVAL
405 * @return ENOTSUP
406 * @return ENOMEM
407 */
408int nic_broadcast_set_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t mode)
409{
410 nic_t *nic_data = (nic_t *) fun->driver_data;
411 fibril_rwlock_write_lock(&nic_data->rxc_lock);
412 int rc = ENOTSUP;
413 if (nic_data->on_broadcast_mode_change) {
414 rc = nic_data->on_broadcast_mode_change(nic_data, mode);
415 }
416 if (rc == EOK) {
417 rc = nic_rxc_broadcast_set_mode(&nic_data->rx_control, mode);
418 }
419 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
420 return rc;
421}
422
423/**
424 * Default implementation of blocked_sources_get method.
425 *
426 * @param fun
427 * @param[in] max_count Max number of addresses that can be written into the
428 * buffer (addr_list).
429 * @param[out] addr_list Buffer for addresses
430 * @param[out] addr_count Number of addresses written into the list
431 *
432 * @return EOK
433 */
434int nic_blocked_sources_get_impl(ddf_fun_t *fun,
435 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
436{
437 nic_t *nic_data = (nic_t *) fun->driver_data;
438 fibril_rwlock_read_lock(&nic_data->rxc_lock);
439 nic_rxc_blocked_sources_get(&nic_data->rx_control,
440 max_count, addr_list, addr_count);
441 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
442 return EOK;
443}
444
445/**
446 * Default implementation of blocked_sources_set method.
447 *
448 * @param fun
449 * @param[in] addr_list List of blocked addresses
450 * @param[in] addr_count Number of addresses in the list
451 *
452 * @return EOK
453 * @return EINVAL
454 * @return ENOTSUP
455 * @return ENOMEM
456 */
457int nic_blocked_sources_set_impl(ddf_fun_t *fun,
458 const nic_address_t *addr_list, size_t addr_count)
459{
460 nic_t *nic_data = (nic_t *) fun->driver_data;
461 fibril_rwlock_write_lock(&nic_data->rxc_lock);
462 if (nic_data->on_blocked_sources_change) {
463 nic_data->on_blocked_sources_change(nic_data, addr_list, addr_count);
464 }
465 int rc = nic_rxc_blocked_sources_set(&nic_data->rx_control,
466 addr_list, addr_count);
467 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
468 return rc;
469}
470
471/**
472 * Default implementation of vlan_get_mask method.
473 *
474 * @param fun
475 * @param[out] mask Current VLAN mask
476 *
477 * @return EOK
478 * @return ENOENT If the mask is not set
479 */
480int nic_vlan_get_mask_impl(ddf_fun_t *fun, nic_vlan_mask_t *mask)
481{
482 nic_t *nic_data = (nic_t *) fun->driver_data;
483 fibril_rwlock_read_lock(&nic_data->rxc_lock);
484 int rc = nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
485 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
486 return rc;
487}
488
489/**
490 * Default implementation of vlan_set_mask method.
491 *
492 * @param fun
493 * @param[in] mask The new VLAN mask
494 *
495 * @return EOK
496 * @return ENOMEM
497 */
498int nic_vlan_set_mask_impl(ddf_fun_t *fun, const nic_vlan_mask_t *mask)
499{
500 nic_t *nic_data = (nic_t *) fun->driver_data;
501 fibril_rwlock_write_lock(&nic_data->rxc_lock);
502 int rc = nic_rxc_vlan_set_mask(&nic_data->rx_control, mask);
503 if (rc == EOK && nic_data->on_vlan_mask_change) {
504 nic_data->on_vlan_mask_change(nic_data, mask);
505 }
506 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
507 return rc;
508}
509
510/**
511 * Default implementation of the wol_virtue_add method.
512 * Create a new WOL virtue.
513 *
514 * @param[in] fun
515 * @param[in] type Type of the virtue
516 * @param[in] data Data required for this virtue (depends on type)
517 * @param[in] length Length of the data
518 * @param[out] filter Identifier of the new virtue
519 *
520 * @return EOK If the operation was successfully completed
521 * @return EINVAL If virtue type is not supported or the data are invalid
522 * @return ELIMIT If the driver does not allow to create more virtues
523 * @return ENOMEM If there was not enough memory to complete the operation
524 */
525int nic_wol_virtue_add_impl(ddf_fun_t *fun, nic_wv_type_t type,
526 const void *data, size_t length, nic_wv_id_t *new_id)
527{
528 nic_t *nic_data = (nic_t *) fun->driver_data;
529 if (nic_data->on_wol_virtue_add == NULL
530 || nic_data->on_wol_virtue_remove == NULL) {
531 return ENOTSUP;
532 }
533 if (type == NIC_WV_NONE || type >= NIC_WV_MAX) {
534 return EINVAL;
535 }
536 if (nic_wol_virtues_verify(type, data, length) != EOK) {
537 return EINVAL;
538 }
539 nic_wol_virtue_t *virtue = malloc(sizeof (nic_wol_virtue_t));
540 if (virtue == NULL) {
541 return ENOMEM;
542 }
543 bzero(virtue, sizeof (nic_wol_virtue_t));
544 if (length != 0) {
545 virtue->data = malloc(length);
546 if (virtue->data == NULL) {
547 free(virtue);
548 return ENOMEM;
549 }
550 memcpy((void *) virtue->data, data, length);
551 }
552 virtue->type = type;
553 virtue->length = length;
554
555 fibril_rwlock_write_lock(&nic_data->wv_lock);
556 /* Check if we haven't reached the maximum */
557 if (nic_data->wol_virtues.caps_max[type] < 0) {
558 fibril_rwlock_write_unlock(&nic_data->wv_lock);
559 return EINVAL;
560 }
561 if ((int) nic_data->wol_virtues.lists_sizes[type] >=
562 nic_data->wol_virtues.caps_max[type]) {
563 fibril_rwlock_write_unlock(&nic_data->wv_lock);
564 return ELIMIT;
565 }
566 /* Call the user-defined add callback */
567 int rc = nic_data->on_wol_virtue_add(nic_data, virtue);
568 if (rc != EOK) {
569 free(virtue->data);
570 free(virtue);
571 fibril_rwlock_write_unlock(&nic_data->wv_lock);
572 return rc;
573 }
574 rc = nic_wol_virtues_add(&nic_data->wol_virtues, virtue);
575 if (rc != EOK) {
576 /* If the adding fails, call user-defined remove callback */
577 nic_data->on_wol_virtue_remove(nic_data, virtue);
578 fibril_rwlock_write_unlock(&nic_data->wv_lock);
579 free(virtue->data);
580 free(virtue);
581 return rc;
582 } else {
583 *new_id = virtue->id;
584 fibril_rwlock_write_unlock(&nic_data->wv_lock);
585 }
586 return EOK;
587}
588
589/**
590 * Default implementation of the wol_virtue_remove method.
591 * Destroys the WOL virtue.
592 *
593 * @param[in] fun
594 * @param[in] id WOL virtue identification
595 *
596 * @return EOK If the operation was successfully completed
597 * @return ENOTSUP If the function is not supported by the driver or device
598 * @return ENOENT If the virtue identifier is not valid.
599 */
600int nic_wol_virtue_remove_impl(ddf_fun_t *fun, nic_wv_id_t id)
601{
602 nic_t *nic_data = (nic_t *) fun->driver_data;
603 if (nic_data->on_wol_virtue_add == NULL
604 || nic_data->on_wol_virtue_remove == NULL) {
605 return ENOTSUP;
606 }
607 fibril_rwlock_write_lock(&nic_data->wv_lock);
608 nic_wol_virtue_t *virtue =
609 nic_wol_virtues_remove(&nic_data->wol_virtues, id);
610 if (virtue == NULL) {
611 fibril_rwlock_write_unlock(&nic_data->wv_lock);
612 return ENOENT;
613 }
614 /* The event handler is called after the filter was removed */
615 nic_data->on_wol_virtue_remove(nic_data, virtue);
616 fibril_rwlock_write_unlock(&nic_data->wv_lock);
617 free(virtue->data);
618 free(virtue);
619 return EOK;
620}
621
622/**
623 * Default implementation of the wol_virtue_probe method.
624 * Queries the type and data of the virtue.
625 *
626 * @param[in] fun
627 * @param[in] id Virtue identifier
628 * @param[out] type Type of the virtue. Can be NULL.
629 * @param[out] data Data used when the virtue was created. Can be NULL.
630 * @param[out] length Length of the data. Can be NULL.
631 *
632 * @return EOK If the operation was successfully completed
633 * @return ENOENT If the virtue identifier is not valid.
634 * @return ENOMEM If there was not enough memory to complete the operation
635 */
636int nic_wol_virtue_probe_impl(ddf_fun_t *fun, nic_wv_id_t id,
637 nic_wv_type_t *type, size_t max_length, void *data, size_t *length)
638{
639 nic_t *nic_data = (nic_t *) fun->driver_data;
640 fibril_rwlock_read_lock(&nic_data->wv_lock);
641 const nic_wol_virtue_t *virtue =
642 nic_wol_virtues_find(&nic_data->wol_virtues, id);
643 if (virtue == NULL) {
644 *type = NIC_WV_NONE;
645 *length = 0;
646 fibril_rwlock_read_unlock(&nic_data->wv_lock);
647 return ENOENT;
648 } else {
649 *type = virtue->type;
650 if (max_length > virtue->length) {
651 max_length = virtue->length;
652 }
653 memcpy(data, virtue->data, max_length);
654 *length = virtue->length;
655 fibril_rwlock_read_unlock(&nic_data->wv_lock);
656 return EOK;
657 }
658}
659
660/**
661 * Default implementation of the wol_virtue_list method.
662 * List filters of the specified type. If NIC_WV_NONE is the type, it lists all
663 * filters.
664 *
665 * @param[in] fun
666 * @param[in] type Type of the virtues
667 * @param[out] virtues Vector of virtue ID's.
668 * @param[out] count Length of the data. Can be NULL.
669 *
670 * @return EOK If the operation was successfully completed
671 * @return ENOENT If the filter identification is not valid.
672 * @return ENOMEM If there was not enough memory to complete the operation
673 */
674int nic_wol_virtue_list_impl(ddf_fun_t *fun, nic_wv_type_t type,
675 size_t max_count, nic_wv_id_t *id_list, size_t *id_count)
676{
677 nic_t *nic_data = (nic_t *) fun->driver_data;
678 fibril_rwlock_read_lock(&nic_data->wv_lock);
679 int rc = nic_wol_virtues_list(&nic_data->wol_virtues, type,
680 max_count, id_list, id_count);
681 fibril_rwlock_read_unlock(&nic_data->wv_lock);
682 return rc;
683}
684
685/**
686 * Default implementation of the wol_virtue_get_caps method.
687 * Queries for the current capabilities for some type of filter.
688 *
689 * @param[in] fun
690 * @param[in] type Type of the virtues
691 * @param[out] count Number of virtues of this type that can be currently set
692 *
693 * @return EOK If the operation was successfully completed
694 */
695int nic_wol_virtue_get_caps_impl(ddf_fun_t *fun, nic_wv_type_t type, int *count)
696{
697 nic_t *nic_data = (nic_t *) fun->driver_data;
698 fibril_rwlock_read_lock(&nic_data->wv_lock);
699 *count = nic_data->wol_virtues.caps_max[type]
700 - (int) nic_data->wol_virtues.lists_sizes[type];
701 fibril_rwlock_read_unlock(&nic_data->wv_lock);
702 return EOK;
703}
704
705/**
706 * Default implementation of the poll_get_mode method.
707 * Queries the current interrupt/poll mode of the NIC
708 *
709 * @param[in] fun
710 * @param[out] mode Current poll mode
711 * @param[out] period Period used in periodic polling. Can be NULL.
712 *
713 * @return EOK If the operation was successfully completed
714 * @return ENOTSUP This function is not supported.
715 * @return EPARTY Error in communication protocol
716 */
717int nic_poll_get_mode_impl(ddf_fun_t *fun,
718 nic_poll_mode_t *mode, struct timeval *period)
719{
720 nic_t *nic_data = (nic_t *) fun->driver_data;
721 fibril_rwlock_read_lock(&nic_data->main_lock);
722 *mode = nic_data->poll_mode;
723 memcpy(period, &nic_data->poll_period, sizeof (struct timeval));
724 fibril_rwlock_read_unlock(&nic_data->main_lock);
725 return EOK;
726}
727
728/**
729 * Default implementation of the poll_set_mode_impl method.
730 * Sets the interrupt/poll mode of the NIC.
731 *
732 * @param[in] fun
733 * @param[in] mode The new poll mode
734 * @param[in] period Period used in periodic polling. Can be NULL.
735 *
736 * @return EOK If the operation was successfully completed
737 * @return ENOTSUP This operation is not supported.
738 * @return EPARTY Error in communication protocol
739 */
740int nic_poll_set_mode_impl(ddf_fun_t *fun,
741 nic_poll_mode_t mode, const struct timeval *period)
742{
743 nic_t *nic_data = (nic_t *) fun->driver_data;
744 /* If the driver does not implement the poll mode change handler it cannot
745 * switch off interrupts and this is not supported. */
746 if (nic_data->on_poll_mode_change == NULL)
747 return ENOTSUP;
748
749 if ((mode == NIC_POLL_ON_DEMAND) && nic_data->on_poll_request == NULL)
750 return ENOTSUP;
751
752 if (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) {
753 if (period == NULL)
754 return EINVAL;
755 if (period->tv_sec == 0 && period->tv_usec == 0)
756 return EINVAL;
757 if (period->tv_sec < 0 || period->tv_usec < 0)
758 return EINVAL;
759 }
760 fibril_rwlock_write_lock(&nic_data->main_lock);
761 int rc = nic_data->on_poll_mode_change(nic_data, mode, period);
762 assert(rc == EOK || rc == ENOTSUP || rc == EINVAL);
763 if (rc == ENOTSUP && (nic_data->on_poll_request != NULL) &&
764 (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) ) {
765
766 rc = nic_data->on_poll_mode_change(nic_data, NIC_POLL_ON_DEMAND, NULL);
767 assert(rc == EOK || rc == ENOTSUP);
768 if (rc == EOK)
769 nic_sw_period_start(nic_data);
770 }
771 if (rc == EOK) {
772 nic_data->poll_mode = mode;
773 if (period)
774 nic_data->poll_period = *period;
775 }
776 fibril_rwlock_write_unlock(&nic_data->main_lock);
777 return rc;
778}
779
780/**
781 * Default implementation of the poll_now method.
782 * Wrapper for the actual poll implementation.
783 *
784 * @param[in] fun
785 *
786 * @return EOK If the NIC was polled
787 * @return ENOTSUP If the function is not supported
788 * @return EINVAL If the NIC is not in state where it allows on demand polling
789 */
790int nic_poll_now_impl(ddf_fun_t *fun) {
791 nic_t *nic_data = (nic_t *) fun->driver_data;
792 fibril_rwlock_read_lock(&nic_data->main_lock);
793 if (nic_data->poll_mode != NIC_POLL_ON_DEMAND) {
794 fibril_rwlock_read_unlock(&nic_data->main_lock);
795 return EINVAL;
796 }
797 if (nic_data->on_poll_request != NULL) {
798 nic_data->on_poll_request(nic_data);
799 fibril_rwlock_read_unlock(&nic_data->main_lock);
800 return EOK;
801 } else {
802 fibril_rwlock_read_unlock(&nic_data->main_lock);
803 return ENOTSUP;
804 }
805}
806
807/** Default implementation of the device_added method
808 *
809 * Just calls nic_ready.
810 *
811 * @param dev
812 *
813 */
814void nic_device_added_impl(ddf_dev_t *dev)
815{
816 nic_ready((nic_t *) dev->driver_data);
817}
818
819/**
820 * Default handler for unknown methods (outside of the NIC interface).
821 * Logs a warning message and returns ENOTSUP to the caller.
822 *
823 * @param fun The DDF function where the method should be called.
824 * @param callid IPC call identifier
825 * @param call IPC call data
826 */
827void nic_default_handler_impl(ddf_fun_t *fun, ipc_callid_t callid,
828 ipc_call_t *call)
829{
830 async_answer_0(callid, ENOTSUP);
831}
832
833/**
834 * Default (empty) OPEN function implementation.
835 *
836 * @param fun The DDF function
837 *
838 * @return EOK always.
839 */
840int nic_open_impl(ddf_fun_t *fun)
841{
842 return EOK;
843}
844
845/**
846 * Default (empty) OPEN function implementation.
847 *
848 * @param fun The DDF function
849 */
850void nic_close_impl(ddf_fun_t *fun)
851{
852}
853
854/** @}
855 */
Note: See TracBrowser for help on using the repository browser.