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

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

NIC should talk to its client via a callback connection with NIC-defined
protocol (was using nil, was connecting via NS).

  • Property mode set to 100644
File size: 24.3 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_ev.h"
43#include "nic_impl.h"
44
45/**
46 * Default implementation of the set_state method. Trivial.
47 *
48 * @param fun
49 * @param[out] state
50 *
51 * @return EOK always.
52 */
53int nic_get_state_impl(ddf_fun_t *fun, nic_device_state_t *state)
54{
55 nic_t *nic_data = (nic_t *) fun->driver_data;
56 fibril_rwlock_read_lock(&nic_data->main_lock);
57 *state = nic_data->state;
58 fibril_rwlock_read_unlock(&nic_data->main_lock);
59 return EOK;
60}
61
62/**
63 * Default implementation of the set_state method. Changes the internal
64 * driver's state, calls the appropriate callback and notifies the NIL service
65 * about this change.
66 *
67 * @param fun
68 * @param state The new device's state
69 *
70 * @return EOK If the state was changed
71 * @return EINVAL If the state cannot be changed
72 */
73int nic_set_state_impl(ddf_fun_t *fun, nic_device_state_t state)
74{
75 if (state >= NIC_STATE_MAX) {
76 return EINVAL;
77 }
78
79 nic_t *nic_data = (nic_t *) fun->driver_data;
80
81 fibril_rwlock_write_lock(&nic_data->main_lock);
82 if (nic_data->state == state) {
83 /* No change, nothing to do */
84 fibril_rwlock_write_unlock(&nic_data->main_lock);
85 return EOK;
86 }
87 if (state == NIC_STATE_ACTIVE) {
88 if (nic_data->client_session == NULL || 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 = nic_ev_addr_changed(nic_data->client_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 nic_ev_device_state(nic_data->client_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_client method.
185 * Creates callback connection to the client.
186 *
187 * @param fun
188 * @param device_id ID of the device as used in higher layers
189 *
190 * @return EOK On success, or negative error code.
191 */
192int nic_callback_create_impl(ddf_fun_t *fun, nic_device_id_t device_id)
193{
194 nic_t *nic = (nic_t *) fun->driver_data;
195 fibril_rwlock_write_lock(&nic->main_lock);
196
197 nic->device_id = device_id;
198
199 nic->client_session = async_callback_receive(EXCHANGE_SERIALIZE);
200 if (nic->client_session == NULL) {
201 fibril_rwlock_write_unlock(&nic->main_lock);
202 return ENOMEM;
203 }
204
205 fibril_rwlock_write_unlock(&nic->main_lock);
206 return EOK;
207}
208
209/**
210 * Default implementation of the get_address method.
211 * Retrieves the NIC's physical address.
212 *
213 * @param fun
214 * @param address Pointer to the structure where the address will be stored.
215 *
216 * @return EOK If the services were bound
217 * @return ELIMIT If the buffer is too short
218 */
219int nic_get_address_impl(ddf_fun_t *fun, nic_address_t *address)
220{
221 assert(address);
222 nic_t *nic_data = (nic_t *) fun->driver_data;
223 fibril_rwlock_read_lock(&nic_data->main_lock);
224 memcpy(address, &nic_data->mac, sizeof (nic_address_t));
225 fibril_rwlock_read_unlock(&nic_data->main_lock);
226 return EOK;
227}
228
229/**
230 * Default implementation of the get_stats method. Copies the statistics from
231 * the drivers data to supplied buffer.
232 *
233 * @param fun
234 * @param[out] stats The buffer for statistics
235 *
236 * @return EOK (cannot fail)
237 */
238int nic_get_stats_impl(ddf_fun_t *fun, nic_device_stats_t *stats)
239{
240 nic_t *nic_data = (nic_t *) fun->driver_data;
241 assert (stats != NULL);
242 fibril_rwlock_read_lock(&nic_data->stats_lock);
243 memcpy(stats, &nic_data->stats, sizeof (nic_device_stats_t));
244 fibril_rwlock_read_unlock(&nic_data->stats_lock);
245 return EOK;
246}
247
248/**
249 * Default implementation of unicast_get_mode method.
250 *
251 * @param fun
252 * @param[out] mode Current operation mode
253 * @param[in] max_count Max number of addresses that can be written into the
254 * buffer (addr_list).
255 * @param[out] addr_list Buffer for addresses
256 * @param[out] addr_count Number of addresses written into the list
257 *
258 * @return EOK
259 */
260int nic_unicast_get_mode_impl(ddf_fun_t *fun, nic_unicast_mode_t *mode,
261 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
262{
263 nic_t *nic_data = (nic_t *) fun->driver_data;
264 fibril_rwlock_read_lock(&nic_data->rxc_lock);
265 nic_rxc_unicast_get_mode(&nic_data->rx_control, mode, max_count,
266 addr_list, addr_count);
267 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
268 return EOK;
269}
270
271/**
272 * Default implementation of unicast_set_mode method.
273 *
274 * @param fun
275 * @param[in] mode New operation mode
276 * @param[in] addr_list List of unicast addresses
277 * @param[in] addr_count Number of addresses in the list
278 *
279 * @return EOK
280 * @return EINVAL
281 * @return ENOTSUP
282 * @return ENOMEM
283 */
284int nic_unicast_set_mode_impl(ddf_fun_t *fun,
285 nic_unicast_mode_t mode, const nic_address_t *addr_list, size_t addr_count)
286{
287 assert((addr_count == 0 && addr_list == NULL)
288 || (addr_count != 0 && addr_list != NULL));
289 size_t i;
290 for (i = 0; i < addr_count; ++i) {
291 if (addr_list[i].address[0] & 1)
292 return EINVAL;
293 }
294
295 nic_t *nic_data = (nic_t *) fun->driver_data;
296 fibril_rwlock_write_lock(&nic_data->rxc_lock);
297 int rc = ENOTSUP;
298 if (nic_data->on_unicast_mode_change) {
299 rc = nic_data->on_unicast_mode_change(nic_data,
300 mode, addr_list, addr_count);
301 }
302 if (rc == EOK) {
303 rc = nic_rxc_unicast_set_mode(&nic_data->rx_control, mode,
304 addr_list, addr_count);
305 /* After changing the mode the addr db gets cleared, therefore we have
306 * to reinsert also the physical address of NIC.
307 */
308 nic_rxc_set_addr(&nic_data->rx_control, NULL, &nic_data->mac);
309 }
310 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
311 return rc;
312}
313
314
315/**
316 * Default implementation of multicast_get_mode method.
317 *
318 * @param fun
319 * @param[out] mode Current operation mode
320 * @param[in] max_count Max number of addresses that can be written into the
321 * buffer (addr_list).
322 * @param[out] addr_list Buffer for addresses
323 * @param[out] addr_count Number of addresses written into the list
324 *
325 * @return EOK
326 */
327int nic_multicast_get_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t *mode,
328 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
329{
330 nic_t *nic_data = (nic_t *) fun->driver_data;
331 fibril_rwlock_read_lock(&nic_data->rxc_lock);
332 nic_rxc_multicast_get_mode(&nic_data->rx_control, mode, max_count,
333 addr_list, addr_count);
334 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
335 return EOK;
336}
337
338/**
339 * Default implementation of multicast_set_mode method.
340 *
341 * @param fun
342 * @param[in] mode New operation mode
343 * @param[in] addr_list List of multicast addresses
344 * @param[in] addr_count Number of addresses in the list
345 *
346 * @return EOK
347 * @return EINVAL
348 * @return ENOTSUP
349 * @return ENOMEM
350 */
351int nic_multicast_set_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t mode,
352 const nic_address_t *addr_list, size_t addr_count)
353{
354 assert((addr_count == 0 && addr_list == NULL)
355 || (addr_count != 0 && addr_list != NULL));
356 size_t i;
357 for (i = 0; i < addr_count; ++i) {
358 if (!(addr_list[i].address[0] & 1))
359 return EINVAL;
360 }
361
362 nic_t *nic_data = (nic_t *) fun->dev->driver_data;
363 fibril_rwlock_write_lock(&nic_data->rxc_lock);
364 int rc = ENOTSUP;
365 if (nic_data->on_multicast_mode_change) {
366 rc = nic_data->on_multicast_mode_change(nic_data, mode, addr_list, addr_count);
367 }
368 if (rc == EOK) {
369 rc = nic_rxc_multicast_set_mode(&nic_data->rx_control, mode,
370 addr_list, addr_count);
371 }
372 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
373 return rc;
374}
375
376/**
377 * Default implementation of broadcast_get_mode method.
378 *
379 * @param fun
380 * @param[out] mode Current operation mode
381 *
382 * @return EOK
383 */
384int nic_broadcast_get_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t *mode)
385{
386 nic_t *nic_data = (nic_t *) fun->driver_data;
387 fibril_rwlock_read_lock(&nic_data->rxc_lock);
388 nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
389 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
390 return EOK;
391}
392
393/**
394 * Default implementation of broadcast_set_mode method.
395 *
396 * @param fun
397 * @param[in] mode New operation mode
398 *
399 * @return EOK
400 * @return EINVAL
401 * @return ENOTSUP
402 * @return ENOMEM
403 */
404int nic_broadcast_set_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t mode)
405{
406 nic_t *nic_data = (nic_t *) fun->driver_data;
407 fibril_rwlock_write_lock(&nic_data->rxc_lock);
408 int rc = ENOTSUP;
409 if (nic_data->on_broadcast_mode_change) {
410 rc = nic_data->on_broadcast_mode_change(nic_data, mode);
411 }
412 if (rc == EOK) {
413 rc = nic_rxc_broadcast_set_mode(&nic_data->rx_control, mode);
414 }
415 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
416 return rc;
417}
418
419/**
420 * Default implementation of blocked_sources_get method.
421 *
422 * @param fun
423 * @param[in] max_count Max number of addresses that can be written into the
424 * buffer (addr_list).
425 * @param[out] addr_list Buffer for addresses
426 * @param[out] addr_count Number of addresses written into the list
427 *
428 * @return EOK
429 */
430int nic_blocked_sources_get_impl(ddf_fun_t *fun,
431 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
432{
433 nic_t *nic_data = (nic_t *) fun->driver_data;
434 fibril_rwlock_read_lock(&nic_data->rxc_lock);
435 nic_rxc_blocked_sources_get(&nic_data->rx_control,
436 max_count, addr_list, addr_count);
437 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
438 return EOK;
439}
440
441/**
442 * Default implementation of blocked_sources_set method.
443 *
444 * @param fun
445 * @param[in] addr_list List of blocked addresses
446 * @param[in] addr_count Number of addresses in the list
447 *
448 * @return EOK
449 * @return EINVAL
450 * @return ENOTSUP
451 * @return ENOMEM
452 */
453int nic_blocked_sources_set_impl(ddf_fun_t *fun,
454 const nic_address_t *addr_list, size_t addr_count)
455{
456 nic_t *nic_data = (nic_t *) fun->driver_data;
457 fibril_rwlock_write_lock(&nic_data->rxc_lock);
458 if (nic_data->on_blocked_sources_change) {
459 nic_data->on_blocked_sources_change(nic_data, addr_list, addr_count);
460 }
461 int rc = nic_rxc_blocked_sources_set(&nic_data->rx_control,
462 addr_list, addr_count);
463 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
464 return rc;
465}
466
467/**
468 * Default implementation of vlan_get_mask method.
469 *
470 * @param fun
471 * @param[out] mask Current VLAN mask
472 *
473 * @return EOK
474 * @return ENOENT If the mask is not set
475 */
476int nic_vlan_get_mask_impl(ddf_fun_t *fun, nic_vlan_mask_t *mask)
477{
478 nic_t *nic_data = (nic_t *) fun->driver_data;
479 fibril_rwlock_read_lock(&nic_data->rxc_lock);
480 int rc = nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
481 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
482 return rc;
483}
484
485/**
486 * Default implementation of vlan_set_mask method.
487 *
488 * @param fun
489 * @param[in] mask The new VLAN mask
490 *
491 * @return EOK
492 * @return ENOMEM
493 */
494int nic_vlan_set_mask_impl(ddf_fun_t *fun, const nic_vlan_mask_t *mask)
495{
496 nic_t *nic_data = (nic_t *) fun->driver_data;
497 fibril_rwlock_write_lock(&nic_data->rxc_lock);
498 int rc = nic_rxc_vlan_set_mask(&nic_data->rx_control, mask);
499 if (rc == EOK && nic_data->on_vlan_mask_change) {
500 nic_data->on_vlan_mask_change(nic_data, mask);
501 }
502 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
503 return rc;
504}
505
506/**
507 * Default implementation of the wol_virtue_add method.
508 * Create a new WOL virtue.
509 *
510 * @param[in] fun
511 * @param[in] type Type of the virtue
512 * @param[in] data Data required for this virtue (depends on type)
513 * @param[in] length Length of the data
514 * @param[out] filter Identifier of the new virtue
515 *
516 * @return EOK If the operation was successfully completed
517 * @return EINVAL If virtue type is not supported or the data are invalid
518 * @return ELIMIT If the driver does not allow to create more virtues
519 * @return ENOMEM If there was not enough memory to complete the operation
520 */
521int nic_wol_virtue_add_impl(ddf_fun_t *fun, nic_wv_type_t type,
522 const void *data, size_t length, nic_wv_id_t *new_id)
523{
524 nic_t *nic_data = (nic_t *) fun->driver_data;
525 if (nic_data->on_wol_virtue_add == NULL
526 || nic_data->on_wol_virtue_remove == NULL) {
527 return ENOTSUP;
528 }
529 if (type == NIC_WV_NONE || type >= NIC_WV_MAX) {
530 return EINVAL;
531 }
532 if (nic_wol_virtues_verify(type, data, length) != EOK) {
533 return EINVAL;
534 }
535 nic_wol_virtue_t *virtue = malloc(sizeof (nic_wol_virtue_t));
536 if (virtue == NULL) {
537 return ENOMEM;
538 }
539 bzero(virtue, sizeof (nic_wol_virtue_t));
540 if (length != 0) {
541 virtue->data = malloc(length);
542 if (virtue->data == NULL) {
543 free(virtue);
544 return ENOMEM;
545 }
546 memcpy((void *) virtue->data, data, length);
547 }
548 virtue->type = type;
549 virtue->length = length;
550
551 fibril_rwlock_write_lock(&nic_data->wv_lock);
552 /* Check if we haven't reached the maximum */
553 if (nic_data->wol_virtues.caps_max[type] < 0) {
554 fibril_rwlock_write_unlock(&nic_data->wv_lock);
555 return EINVAL;
556 }
557 if ((int) nic_data->wol_virtues.lists_sizes[type] >=
558 nic_data->wol_virtues.caps_max[type]) {
559 fibril_rwlock_write_unlock(&nic_data->wv_lock);
560 return ELIMIT;
561 }
562 /* Call the user-defined add callback */
563 int rc = nic_data->on_wol_virtue_add(nic_data, virtue);
564 if (rc != EOK) {
565 free(virtue->data);
566 free(virtue);
567 fibril_rwlock_write_unlock(&nic_data->wv_lock);
568 return rc;
569 }
570 rc = nic_wol_virtues_add(&nic_data->wol_virtues, virtue);
571 if (rc != EOK) {
572 /* If the adding fails, call user-defined remove callback */
573 nic_data->on_wol_virtue_remove(nic_data, virtue);
574 fibril_rwlock_write_unlock(&nic_data->wv_lock);
575 free(virtue->data);
576 free(virtue);
577 return rc;
578 } else {
579 *new_id = virtue->id;
580 fibril_rwlock_write_unlock(&nic_data->wv_lock);
581 }
582 return EOK;
583}
584
585/**
586 * Default implementation of the wol_virtue_remove method.
587 * Destroys the WOL virtue.
588 *
589 * @param[in] fun
590 * @param[in] id WOL virtue identification
591 *
592 * @return EOK If the operation was successfully completed
593 * @return ENOTSUP If the function is not supported by the driver or device
594 * @return ENOENT If the virtue identifier is not valid.
595 */
596int nic_wol_virtue_remove_impl(ddf_fun_t *fun, nic_wv_id_t id)
597{
598 nic_t *nic_data = (nic_t *) fun->driver_data;
599 if (nic_data->on_wol_virtue_add == NULL
600 || nic_data->on_wol_virtue_remove == NULL) {
601 return ENOTSUP;
602 }
603 fibril_rwlock_write_lock(&nic_data->wv_lock);
604 nic_wol_virtue_t *virtue =
605 nic_wol_virtues_remove(&nic_data->wol_virtues, id);
606 if (virtue == NULL) {
607 fibril_rwlock_write_unlock(&nic_data->wv_lock);
608 return ENOENT;
609 }
610 /* The event handler is called after the filter was removed */
611 nic_data->on_wol_virtue_remove(nic_data, virtue);
612 fibril_rwlock_write_unlock(&nic_data->wv_lock);
613 free(virtue->data);
614 free(virtue);
615 return EOK;
616}
617
618/**
619 * Default implementation of the wol_virtue_probe method.
620 * Queries the type and data of the virtue.
621 *
622 * @param[in] fun
623 * @param[in] id Virtue identifier
624 * @param[out] type Type of the virtue. Can be NULL.
625 * @param[out] data Data used when the virtue was created. Can be NULL.
626 * @param[out] length Length of the data. Can be NULL.
627 *
628 * @return EOK If the operation was successfully completed
629 * @return ENOENT If the virtue identifier is not valid.
630 * @return ENOMEM If there was not enough memory to complete the operation
631 */
632int nic_wol_virtue_probe_impl(ddf_fun_t *fun, nic_wv_id_t id,
633 nic_wv_type_t *type, size_t max_length, void *data, size_t *length)
634{
635 nic_t *nic_data = (nic_t *) fun->driver_data;
636 fibril_rwlock_read_lock(&nic_data->wv_lock);
637 const nic_wol_virtue_t *virtue =
638 nic_wol_virtues_find(&nic_data->wol_virtues, id);
639 if (virtue == NULL) {
640 *type = NIC_WV_NONE;
641 *length = 0;
642 fibril_rwlock_read_unlock(&nic_data->wv_lock);
643 return ENOENT;
644 } else {
645 *type = virtue->type;
646 if (max_length > virtue->length) {
647 max_length = virtue->length;
648 }
649 memcpy(data, virtue->data, max_length);
650 *length = virtue->length;
651 fibril_rwlock_read_unlock(&nic_data->wv_lock);
652 return EOK;
653 }
654}
655
656/**
657 * Default implementation of the wol_virtue_list method.
658 * List filters of the specified type. If NIC_WV_NONE is the type, it lists all
659 * filters.
660 *
661 * @param[in] fun
662 * @param[in] type Type of the virtues
663 * @param[out] virtues Vector of virtue ID's.
664 * @param[out] count Length of the data. Can be NULL.
665 *
666 * @return EOK If the operation was successfully completed
667 * @return ENOENT If the filter identification is not valid.
668 * @return ENOMEM If there was not enough memory to complete the operation
669 */
670int nic_wol_virtue_list_impl(ddf_fun_t *fun, nic_wv_type_t type,
671 size_t max_count, nic_wv_id_t *id_list, size_t *id_count)
672{
673 nic_t *nic_data = (nic_t *) fun->driver_data;
674 fibril_rwlock_read_lock(&nic_data->wv_lock);
675 int rc = nic_wol_virtues_list(&nic_data->wol_virtues, type,
676 max_count, id_list, id_count);
677 fibril_rwlock_read_unlock(&nic_data->wv_lock);
678 return rc;
679}
680
681/**
682 * Default implementation of the wol_virtue_get_caps method.
683 * Queries for the current capabilities for some type of filter.
684 *
685 * @param[in] fun
686 * @param[in] type Type of the virtues
687 * @param[out] count Number of virtues of this type that can be currently set
688 *
689 * @return EOK If the operation was successfully completed
690 */
691int nic_wol_virtue_get_caps_impl(ddf_fun_t *fun, nic_wv_type_t type, int *count)
692{
693 nic_t *nic_data = (nic_t *) fun->driver_data;
694 fibril_rwlock_read_lock(&nic_data->wv_lock);
695 *count = nic_data->wol_virtues.caps_max[type]
696 - (int) nic_data->wol_virtues.lists_sizes[type];
697 fibril_rwlock_read_unlock(&nic_data->wv_lock);
698 return EOK;
699}
700
701/**
702 * Default implementation of the poll_get_mode method.
703 * Queries the current interrupt/poll mode of the NIC
704 *
705 * @param[in] fun
706 * @param[out] mode Current poll mode
707 * @param[out] period Period used in periodic polling. Can be NULL.
708 *
709 * @return EOK If the operation was successfully completed
710 * @return ENOTSUP This function is not supported.
711 * @return EPARTY Error in communication protocol
712 */
713int nic_poll_get_mode_impl(ddf_fun_t *fun,
714 nic_poll_mode_t *mode, struct timeval *period)
715{
716 nic_t *nic_data = (nic_t *) fun->driver_data;
717 fibril_rwlock_read_lock(&nic_data->main_lock);
718 *mode = nic_data->poll_mode;
719 memcpy(period, &nic_data->poll_period, sizeof (struct timeval));
720 fibril_rwlock_read_unlock(&nic_data->main_lock);
721 return EOK;
722}
723
724/**
725 * Default implementation of the poll_set_mode_impl method.
726 * Sets the interrupt/poll mode of the NIC.
727 *
728 * @param[in] fun
729 * @param[in] mode The new poll mode
730 * @param[in] period Period used in periodic polling. Can be NULL.
731 *
732 * @return EOK If the operation was successfully completed
733 * @return ENOTSUP This operation is not supported.
734 * @return EPARTY Error in communication protocol
735 */
736int nic_poll_set_mode_impl(ddf_fun_t *fun,
737 nic_poll_mode_t mode, const struct timeval *period)
738{
739 nic_t *nic_data = (nic_t *) fun->driver_data;
740 /* If the driver does not implement the poll mode change handler it cannot
741 * switch off interrupts and this is not supported. */
742 if (nic_data->on_poll_mode_change == NULL)
743 return ENOTSUP;
744
745 if ((mode == NIC_POLL_ON_DEMAND) && nic_data->on_poll_request == NULL)
746 return ENOTSUP;
747
748 if (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) {
749 if (period == NULL)
750 return EINVAL;
751 if (period->tv_sec == 0 && period->tv_usec == 0)
752 return EINVAL;
753 if (period->tv_sec < 0 || period->tv_usec < 0)
754 return EINVAL;
755 }
756 fibril_rwlock_write_lock(&nic_data->main_lock);
757 int rc = nic_data->on_poll_mode_change(nic_data, mode, period);
758 assert(rc == EOK || rc == ENOTSUP || rc == EINVAL);
759 if (rc == ENOTSUP && (nic_data->on_poll_request != NULL) &&
760 (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) ) {
761
762 rc = nic_data->on_poll_mode_change(nic_data, NIC_POLL_ON_DEMAND, NULL);
763 assert(rc == EOK || rc == ENOTSUP);
764 if (rc == EOK)
765 nic_sw_period_start(nic_data);
766 }
767 if (rc == EOK) {
768 nic_data->poll_mode = mode;
769 if (period)
770 nic_data->poll_period = *period;
771 }
772 fibril_rwlock_write_unlock(&nic_data->main_lock);
773 return rc;
774}
775
776/**
777 * Default implementation of the poll_now method.
778 * Wrapper for the actual poll implementation.
779 *
780 * @param[in] fun
781 *
782 * @return EOK If the NIC was polled
783 * @return ENOTSUP If the function is not supported
784 * @return EINVAL If the NIC is not in state where it allows on demand polling
785 */
786int nic_poll_now_impl(ddf_fun_t *fun) {
787 nic_t *nic_data = (nic_t *) fun->driver_data;
788 fibril_rwlock_read_lock(&nic_data->main_lock);
789 if (nic_data->poll_mode != NIC_POLL_ON_DEMAND) {
790 fibril_rwlock_read_unlock(&nic_data->main_lock);
791 return EINVAL;
792 }
793 if (nic_data->on_poll_request != NULL) {
794 nic_data->on_poll_request(nic_data);
795 fibril_rwlock_read_unlock(&nic_data->main_lock);
796 return EOK;
797 } else {
798 fibril_rwlock_read_unlock(&nic_data->main_lock);
799 return ENOTSUP;
800 }
801}
802
803/**
804 * Default handler for unknown methods (outside of the NIC interface).
805 * Logs a warning message and returns ENOTSUP to the caller.
806 *
807 * @param fun The DDF function where the method should be called.
808 * @param callid IPC call identifier
809 * @param call IPC call data
810 */
811void nic_default_handler_impl(ddf_fun_t *fun, ipc_callid_t callid,
812 ipc_call_t *call)
813{
814 async_answer_0(callid, ENOTSUP);
815}
816
817/**
818 * Default (empty) OPEN function implementation.
819 *
820 * @param fun The DDF function
821 *
822 * @return EOK always.
823 */
824int nic_open_impl(ddf_fun_t *fun)
825{
826 return EOK;
827}
828
829/**
830 * Default (empty) OPEN function implementation.
831 *
832 * @param fun The DDF function
833 */
834void nic_close_impl(ddf_fun_t *fun)
835{
836}
837
838/** @}
839 */
Note: See TracBrowser for help on using the repository browser.