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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 7b87e1d was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • 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 <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 */
54errno_t nic_get_state_impl(ddf_fun_t *fun, nic_device_state_t *state)
55{
56 nic_t *nic_data = nic_get_from_ddf_fun(fun);
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 */
74errno_t 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_get_from_ddf_fun(fun);
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 errno_t 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 errno_t 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 /*
126 * We have already ran the on stopped handler, even if we
127 * terminated the state change we would end up in undefined state.
128 * Therefore we just log the problem.
129 */
130 }
131
132 fibril_rwlock_write_lock(&nic_data->stats_lock);
133 memset(&nic_data->stats, 0, sizeof(nic_device_stats_t));
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,
140 &nic_data->default_mac);
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
154 nic_ev_device_state(nic_data->client_session, state);
155
156 fibril_rwlock_write_unlock(&nic_data->main_lock);
157
158 return EOK;
159}
160
161/**
162 * Default implementation of the send_frame method.
163 * Send messages to the network.
164 *
165 * @param fun
166 * @param data Frame data
167 * @param size Frame size in bytes
168 *
169 * @return EOK If the message was sent
170 * @return EBUSY If the device is not in state when the frame can be sent.
171 */
172errno_t nic_send_frame_impl(ddf_fun_t *fun, void *data, size_t size)
173{
174 nic_t *nic_data = nic_get_from_ddf_fun(fun);
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
182 nic_data->send_frame(nic_data, data, size);
183 fibril_rwlock_read_unlock(&nic_data->main_lock);
184 return EOK;
185}
186
187/**
188 * Default implementation of the connect_client method.
189 * Creates callback connection to the client.
190 *
191 * @param fun
192 *
193 * @return EOK On success, or an error code.
194 */
195errno_t nic_callback_create_impl(ddf_fun_t *fun)
196{
197 nic_t *nic = nic_get_from_ddf_fun(fun);
198 fibril_rwlock_write_lock(&nic->main_lock);
199
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;
204 }
205
206 fibril_rwlock_write_unlock(&nic->main_lock);
207 return EOK;
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 */
220errno_t nic_get_address_impl(ddf_fun_t *fun, nic_address_t *address)
221{
222 assert(address);
223 nic_t *nic_data = nic_get_from_ddf_fun(fun);
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 */
239errno_t nic_get_stats_impl(ddf_fun_t *fun, nic_device_stats_t *stats)
240{
241 nic_t *nic_data = nic_get_from_ddf_fun(fun);
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 */
261errno_t nic_unicast_get_mode_impl(ddf_fun_t *fun, nic_unicast_mode_t *mode,
262 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
263{
264 nic_t *nic_data = nic_get_from_ddf_fun(fun);
265 fibril_rwlock_read_lock(&nic_data->rxc_lock);
266 nic_rxc_unicast_get_mode(&nic_data->rx_control, mode, max_count,
267 addr_list, addr_count);
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 */
285errno_t nic_unicast_set_mode_impl(ddf_fun_t *fun,
286 nic_unicast_mode_t mode, const nic_address_t *addr_list, size_t addr_count)
287{
288 assert((addr_count == 0 && addr_list == NULL) ||
289 (addr_count != 0 && addr_list != NULL));
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
296 nic_t *nic_data = nic_get_from_ddf_fun(fun);
297 fibril_rwlock_write_lock(&nic_data->rxc_lock);
298 errno_t rc = ENOTSUP;
299 if (nic_data->on_unicast_mode_change) {
300 rc = nic_data->on_unicast_mode_change(nic_data,
301 mode, addr_list, addr_count);
302 }
303 if (rc == EOK) {
304 rc = nic_rxc_unicast_set_mode(&nic_data->rx_control, mode,
305 addr_list, addr_count);
306 /*
307 * After changing the mode the addr db gets cleared, therefore we have
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/**
318 * Default implementation of multicast_get_mode method.
319 *
320 * @param fun
321 * @param[out] mode Current operation mode
322 * @param[in] max_count Max number of addresses that can be written into the
323 * buffer (addr_list).
324 * @param[out] addr_list Buffer for addresses
325 * @param[out] addr_count Number of addresses written into the list
326 *
327 * @return EOK
328 */
329errno_t nic_multicast_get_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t *mode,
330 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
331{
332 nic_t *nic_data = nic_get_from_ddf_fun(fun);
333 fibril_rwlock_read_lock(&nic_data->rxc_lock);
334 nic_rxc_multicast_get_mode(&nic_data->rx_control, mode, max_count,
335 addr_list, addr_count);
336 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
337 return EOK;
338}
339
340/**
341 * Default implementation of multicast_set_mode method.
342 *
343 * @param fun
344 * @param[in] mode New operation mode
345 * @param[in] addr_list List of multicast addresses
346 * @param[in] addr_count Number of addresses in the list
347 *
348 * @return EOK
349 * @return EINVAL
350 * @return ENOTSUP
351 * @return ENOMEM
352 */
353errno_t nic_multicast_set_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t mode,
354 const nic_address_t *addr_list, size_t addr_count)
355{
356 assert((addr_count == 0 && addr_list == NULL) ||
357 (addr_count != 0 && addr_list != NULL));
358 size_t i;
359 for (i = 0; i < addr_count; ++i) {
360 if (!(addr_list[i].address[0] & 1))
361 return EINVAL;
362 }
363
364 nic_t *nic_data = nic_get_from_ddf_fun(fun);
365 fibril_rwlock_write_lock(&nic_data->rxc_lock);
366 errno_t rc = ENOTSUP;
367 if (nic_data->on_multicast_mode_change) {
368 rc = nic_data->on_multicast_mode_change(nic_data, mode, addr_list, addr_count);
369 }
370 if (rc == EOK) {
371 rc = nic_rxc_multicast_set_mode(&nic_data->rx_control, mode,
372 addr_list, addr_count);
373 }
374 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
375 return rc;
376}
377
378/**
379 * Default implementation of broadcast_get_mode method.
380 *
381 * @param fun
382 * @param[out] mode Current operation mode
383 *
384 * @return EOK
385 */
386errno_t nic_broadcast_get_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t *mode)
387{
388 nic_t *nic_data = nic_get_from_ddf_fun(fun);
389 fibril_rwlock_read_lock(&nic_data->rxc_lock);
390 nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode);
391 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
392 return EOK;
393}
394
395/**
396 * Default implementation of broadcast_set_mode method.
397 *
398 * @param fun
399 * @param[in] mode New operation mode
400 *
401 * @return EOK
402 * @return EINVAL
403 * @return ENOTSUP
404 * @return ENOMEM
405 */
406errno_t nic_broadcast_set_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t mode)
407{
408 nic_t *nic_data = nic_get_from_ddf_fun(fun);
409 fibril_rwlock_write_lock(&nic_data->rxc_lock);
410 errno_t rc = ENOTSUP;
411 if (nic_data->on_broadcast_mode_change) {
412 rc = nic_data->on_broadcast_mode_change(nic_data, mode);
413 }
414 if (rc == EOK) {
415 rc = nic_rxc_broadcast_set_mode(&nic_data->rx_control, mode);
416 }
417 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
418 return rc;
419}
420
421/**
422 * Default implementation of blocked_sources_get method.
423 *
424 * @param fun
425 * @param[in] max_count Max number of addresses that can be written into the
426 * buffer (addr_list).
427 * @param[out] addr_list Buffer for addresses
428 * @param[out] addr_count Number of addresses written into the list
429 *
430 * @return EOK
431 */
432errno_t nic_blocked_sources_get_impl(ddf_fun_t *fun,
433 size_t max_count, nic_address_t *addr_list, size_t *addr_count)
434{
435 nic_t *nic_data = nic_get_from_ddf_fun(fun);
436 fibril_rwlock_read_lock(&nic_data->rxc_lock);
437 nic_rxc_blocked_sources_get(&nic_data->rx_control,
438 max_count, addr_list, addr_count);
439 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
440 return EOK;
441}
442
443/**
444 * Default implementation of blocked_sources_set method.
445 *
446 * @param fun
447 * @param[in] addr_list List of blocked addresses
448 * @param[in] addr_count Number of addresses in the list
449 *
450 * @return EOK
451 * @return EINVAL
452 * @return ENOTSUP
453 * @return ENOMEM
454 */
455errno_t nic_blocked_sources_set_impl(ddf_fun_t *fun,
456 const nic_address_t *addr_list, size_t addr_count)
457{
458 nic_t *nic_data = nic_get_from_ddf_fun(fun);
459 fibril_rwlock_write_lock(&nic_data->rxc_lock);
460 if (nic_data->on_blocked_sources_change) {
461 nic_data->on_blocked_sources_change(nic_data, addr_list, addr_count);
462 }
463 errno_t rc = nic_rxc_blocked_sources_set(&nic_data->rx_control,
464 addr_list, addr_count);
465 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
466 return rc;
467}
468
469/**
470 * Default implementation of vlan_get_mask method.
471 *
472 * @param fun
473 * @param[out] mask Current VLAN mask
474 *
475 * @return EOK
476 * @return ENOENT If the mask is not set
477 */
478errno_t nic_vlan_get_mask_impl(ddf_fun_t *fun, nic_vlan_mask_t *mask)
479{
480 nic_t *nic_data = nic_get_from_ddf_fun(fun);
481 fibril_rwlock_read_lock(&nic_data->rxc_lock);
482 errno_t rc = nic_rxc_vlan_get_mask(&nic_data->rx_control, mask);
483 fibril_rwlock_read_unlock(&nic_data->rxc_lock);
484 return rc;
485}
486
487/**
488 * Default implementation of vlan_set_mask method.
489 *
490 * @param fun
491 * @param[in] mask The new VLAN mask
492 *
493 * @return EOK
494 * @return ENOMEM
495 */
496errno_t nic_vlan_set_mask_impl(ddf_fun_t *fun, const nic_vlan_mask_t *mask)
497{
498 nic_t *nic_data = nic_get_from_ddf_fun(fun);
499 fibril_rwlock_write_lock(&nic_data->rxc_lock);
500 errno_t rc = nic_rxc_vlan_set_mask(&nic_data->rx_control, mask);
501 if (rc == EOK && nic_data->on_vlan_mask_change) {
502 nic_data->on_vlan_mask_change(nic_data, mask);
503 }
504 fibril_rwlock_write_unlock(&nic_data->rxc_lock);
505 return rc;
506}
507
508/**
509 * Default implementation of the wol_virtue_add method.
510 * Create a new WOL virtue.
511 *
512 * @param[in] fun
513 * @param[in] type Type of the virtue
514 * @param[in] data Data required for this virtue (depends on type)
515 * @param[in] length Length of the data
516 * @param[out] filter Identifier of the new virtue
517 *
518 * @return EOK If the operation was successfully completed
519 * @return EINVAL If virtue type is not supported or the data are invalid
520 * @return ELIMIT If the driver does not allow to create more virtues
521 * @return ENOMEM If there was not enough memory to complete the operation
522 */
523errno_t nic_wol_virtue_add_impl(ddf_fun_t *fun, nic_wv_type_t type,
524 const void *data, size_t length, nic_wv_id_t *new_id)
525{
526 nic_t *nic_data = nic_get_from_ddf_fun(fun);
527 if (nic_data->on_wol_virtue_add == NULL ||
528 nic_data->on_wol_virtue_remove == NULL) {
529 return ENOTSUP;
530 }
531 if (type == NIC_WV_NONE || type >= NIC_WV_MAX) {
532 return EINVAL;
533 }
534 if (nic_wol_virtues_verify(type, data, length) != EOK) {
535 return EINVAL;
536 }
537 nic_wol_virtue_t *virtue = malloc(sizeof (nic_wol_virtue_t));
538 if (virtue == NULL) {
539 return ENOMEM;
540 }
541 memset(virtue, 0, sizeof(nic_wol_virtue_t));
542 if (length != 0) {
543 virtue->data = malloc(length);
544 if (virtue->data == NULL) {
545 free(virtue);
546 return ENOMEM;
547 }
548 memcpy((void *) virtue->data, data, length);
549 }
550 virtue->type = type;
551 virtue->length = length;
552
553 fibril_rwlock_write_lock(&nic_data->wv_lock);
554 /* Check if we haven't reached the maximum */
555 if (nic_data->wol_virtues.caps_max[type] < 0) {
556 fibril_rwlock_write_unlock(&nic_data->wv_lock);
557 return EINVAL;
558 }
559 if ((int) nic_data->wol_virtues.lists_sizes[type] >=
560 nic_data->wol_virtues.caps_max[type]) {
561 fibril_rwlock_write_unlock(&nic_data->wv_lock);
562 return ELIMIT;
563 }
564 /* Call the user-defined add callback */
565 errno_t rc = nic_data->on_wol_virtue_add(nic_data, virtue);
566 if (rc != EOK) {
567 free(virtue->data);
568 free(virtue);
569 fibril_rwlock_write_unlock(&nic_data->wv_lock);
570 return rc;
571 }
572 rc = nic_wol_virtues_add(&nic_data->wol_virtues, virtue);
573 if (rc != EOK) {
574 /* If the adding fails, call user-defined remove callback */
575 nic_data->on_wol_virtue_remove(nic_data, virtue);
576 fibril_rwlock_write_unlock(&nic_data->wv_lock);
577 free(virtue->data);
578 free(virtue);
579 return rc;
580 } else {
581 *new_id = virtue->id;
582 fibril_rwlock_write_unlock(&nic_data->wv_lock);
583 }
584 return EOK;
585}
586
587/**
588 * Default implementation of the wol_virtue_remove method.
589 * Destroys the WOL virtue.
590 *
591 * @param[in] fun
592 * @param[in] id WOL virtue identification
593 *
594 * @return EOK If the operation was successfully completed
595 * @return ENOTSUP If the function is not supported by the driver or device
596 * @return ENOENT If the virtue identifier is not valid.
597 */
598errno_t nic_wol_virtue_remove_impl(ddf_fun_t *fun, nic_wv_id_t id)
599{
600 nic_t *nic_data = nic_get_from_ddf_fun(fun);
601 if (nic_data->on_wol_virtue_add == NULL ||
602 nic_data->on_wol_virtue_remove == NULL) {
603 return ENOTSUP;
604 }
605 fibril_rwlock_write_lock(&nic_data->wv_lock);
606 nic_wol_virtue_t *virtue =
607 nic_wol_virtues_remove(&nic_data->wol_virtues, id);
608 if (virtue == NULL) {
609 fibril_rwlock_write_unlock(&nic_data->wv_lock);
610 return ENOENT;
611 }
612 /* The event handler is called after the filter was removed */
613 nic_data->on_wol_virtue_remove(nic_data, virtue);
614 fibril_rwlock_write_unlock(&nic_data->wv_lock);
615 free(virtue->data);
616 free(virtue);
617 return EOK;
618}
619
620/**
621 * Default implementation of the wol_virtue_probe method.
622 * Queries the type and data of the virtue.
623 *
624 * @param[in] fun
625 * @param[in] id Virtue identifier
626 * @param[out] type Type of the virtue. Can be NULL.
627 * @param[out] data Data used when the virtue was created. Can be NULL.
628 * @param[out] length Length of the data. Can be NULL.
629 *
630 * @return EOK If the operation was successfully completed
631 * @return ENOENT If the virtue identifier is not valid.
632 * @return ENOMEM If there was not enough memory to complete the operation
633 */
634errno_t nic_wol_virtue_probe_impl(ddf_fun_t *fun, nic_wv_id_t id,
635 nic_wv_type_t *type, size_t max_length, void *data, size_t *length)
636{
637 nic_t *nic_data = nic_get_from_ddf_fun(fun);
638 fibril_rwlock_read_lock(&nic_data->wv_lock);
639 const nic_wol_virtue_t *virtue =
640 nic_wol_virtues_find(&nic_data->wol_virtues, id);
641 if (virtue == NULL) {
642 *type = NIC_WV_NONE;
643 *length = 0;
644 fibril_rwlock_read_unlock(&nic_data->wv_lock);
645 return ENOENT;
646 } else {
647 *type = virtue->type;
648 if (max_length > virtue->length) {
649 max_length = virtue->length;
650 }
651 memcpy(data, virtue->data, max_length);
652 *length = virtue->length;
653 fibril_rwlock_read_unlock(&nic_data->wv_lock);
654 return EOK;
655 }
656}
657
658/**
659 * Default implementation of the wol_virtue_list method.
660 * List filters of the specified type. If NIC_WV_NONE is the type, it lists all
661 * filters.
662 *
663 * @param[in] fun
664 * @param[in] type Type of the virtues
665 * @param[out] virtues Vector of virtue ID's.
666 * @param[out] count Length of the data. Can be NULL.
667 *
668 * @return EOK If the operation was successfully completed
669 * @return ENOENT If the filter identification is not valid.
670 * @return ENOMEM If there was not enough memory to complete the operation
671 */
672errno_t nic_wol_virtue_list_impl(ddf_fun_t *fun, nic_wv_type_t type,
673 size_t max_count, nic_wv_id_t *id_list, size_t *id_count)
674{
675 nic_t *nic_data = nic_get_from_ddf_fun(fun);
676 fibril_rwlock_read_lock(&nic_data->wv_lock);
677 errno_t rc = nic_wol_virtues_list(&nic_data->wol_virtues, type,
678 max_count, id_list, id_count);
679 fibril_rwlock_read_unlock(&nic_data->wv_lock);
680 return rc;
681}
682
683/**
684 * Default implementation of the wol_virtue_get_caps method.
685 * Queries for the current capabilities for some type of filter.
686 *
687 * @param[in] fun
688 * @param[in] type Type of the virtues
689 * @param[out] count Number of virtues of this type that can be currently set
690 *
691 * @return EOK If the operation was successfully completed
692 */
693errno_t nic_wol_virtue_get_caps_impl(ddf_fun_t *fun, nic_wv_type_t type, int *count)
694{
695 nic_t *nic_data = nic_get_from_ddf_fun(fun);
696 fibril_rwlock_read_lock(&nic_data->wv_lock);
697 *count = nic_data->wol_virtues.caps_max[type] -
698 (int) nic_data->wol_virtues.lists_sizes[type];
699 fibril_rwlock_read_unlock(&nic_data->wv_lock);
700 return EOK;
701}
702
703/**
704 * Default implementation of the poll_get_mode method.
705 * Queries the current interrupt/poll mode of the NIC
706 *
707 * @param[in] fun
708 * @param[out] mode Current poll mode
709 * @param[out] period Period used in periodic polling. Can be NULL.
710 *
711 * @return EOK If the operation was successfully completed
712 * @return ENOTSUP This function is not supported.
713 * @return EPARTY Error in communication protocol
714 */
715errno_t nic_poll_get_mode_impl(ddf_fun_t *fun,
716 nic_poll_mode_t *mode, struct timeval *period)
717{
718 nic_t *nic_data = nic_get_from_ddf_fun(fun);
719 fibril_rwlock_read_lock(&nic_data->main_lock);
720 *mode = nic_data->poll_mode;
721 memcpy(period, &nic_data->poll_period, sizeof(struct timeval));
722 fibril_rwlock_read_unlock(&nic_data->main_lock);
723 return EOK;
724}
725
726/**
727 * Default implementation of the poll_set_mode_impl method.
728 * Sets the interrupt/poll mode of the NIC.
729 *
730 * @param[in] fun
731 * @param[in] mode The new poll mode
732 * @param[in] period Period used in periodic polling. Can be NULL.
733 *
734 * @return EOK If the operation was successfully completed
735 * @return ENOTSUP This operation is not supported.
736 * @return EPARTY Error in communication protocol
737 */
738errno_t nic_poll_set_mode_impl(ddf_fun_t *fun,
739 nic_poll_mode_t mode, const struct timeval *period)
740{
741 nic_t *nic_data = nic_get_from_ddf_fun(fun);
742 /*
743 * If the driver does not implement the poll mode change handler it cannot
744 * switch off interrupts and this is not supported.
745 */
746 if (nic_data->on_poll_mode_change == NULL)
747 return ENOTSUP;
748
749 if ((mode == NIC_POLL_ON_DEMAND) && nic_data->on_poll_request == NULL)
750 return ENOTSUP;
751
752 if (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) {
753 if (period == NULL)
754 return EINVAL;
755 if (period->tv_sec == 0 && period->tv_usec == 0)
756 return EINVAL;
757 if (period->tv_sec < 0 || period->tv_usec < 0)
758 return EINVAL;
759 }
760 fibril_rwlock_write_lock(&nic_data->main_lock);
761 errno_t rc = nic_data->on_poll_mode_change(nic_data, mode, period);
762 assert(rc == EOK || rc == ENOTSUP || rc == EINVAL);
763 if (rc == ENOTSUP && (nic_data->on_poll_request != NULL) &&
764 (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC)) {
765
766 rc = nic_data->on_poll_mode_change(nic_data, NIC_POLL_ON_DEMAND, NULL);
767 assert(rc == EOK || rc == ENOTSUP);
768 if (rc == EOK)
769 nic_sw_period_start(nic_data);
770 }
771 if (rc == EOK) {
772 nic_data->poll_mode = mode;
773 if (period)
774 nic_data->poll_period = *period;
775 }
776 fibril_rwlock_write_unlock(&nic_data->main_lock);
777 return rc;
778}
779
780/**
781 * Default implementation of the poll_now method.
782 * Wrapper for the actual poll implementation.
783 *
784 * @param[in] fun
785 *
786 * @return EOK If the NIC was polled
787 * @return ENOTSUP If the function is not supported
788 * @return EINVAL If the NIC is not in state where it allows on demand polling
789 */
790errno_t nic_poll_now_impl(ddf_fun_t *fun)
791{
792 nic_t *nic_data = nic_get_from_ddf_fun(fun);
793 fibril_rwlock_read_lock(&nic_data->main_lock);
794 if (nic_data->poll_mode != NIC_POLL_ON_DEMAND) {
795 fibril_rwlock_read_unlock(&nic_data->main_lock);
796 return EINVAL;
797 }
798 if (nic_data->on_poll_request != NULL) {
799 nic_data->on_poll_request(nic_data);
800 fibril_rwlock_read_unlock(&nic_data->main_lock);
801 return EOK;
802 } else {
803 fibril_rwlock_read_unlock(&nic_data->main_lock);
804 return ENOTSUP;
805 }
806}
807
808/**
809 * Default handler for unknown methods (outside of the NIC interface).
810 * Logs a warning message and returns ENOTSUP to the caller.
811 *
812 * @param fun The DDF function where the method should be called.
813 * @param call IPC call data
814 *
815 */
816void nic_default_handler_impl(ddf_fun_t *fun, ipc_call_t *call)
817{
818 async_answer_0(call, ENOTSUP);
819}
820
821/**
822 * Default (empty) OPEN function implementation.
823 *
824 * @param fun The DDF function
825 *
826 * @return EOK always.
827 */
828errno_t nic_open_impl(ddf_fun_t *fun)
829{
830 return EOK;
831}
832
833/**
834 * Default (empty) OPEN function implementation.
835 *
836 * @param fun The DDF function
837 */
838void nic_close_impl(ddf_fun_t *fun)
839{
840}
841
842/** @}
843 */
Note: See TracBrowser for help on using the repository browser.