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

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

NIC does not need nic_device_id_t. Now it exists just inside net. Not sure if
we care to rename it since net is going away soon, anyway.

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