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

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

libnic no longer needs net_session.

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