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

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

Fix vertical spacing with new Ccheck revision.

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