/* * Copyright (c) 2011 Radim Vansa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * @addtogroup libnic * @{ */ /** * @file * @brief Default DDF NIC interface methods implementations */ #include #include #include #include #include "nic_driver.h" #include "nic_ev.h" #include "nic_impl.h" /** * Default implementation of the set_state method. Trivial. * * @param fun * @param[out] state * * @return EOK always. */ int nic_get_state_impl(ddf_fun_t *fun, nic_device_state_t *state) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->main_lock); *state = nic_data->state; fibril_rwlock_read_unlock(&nic_data->main_lock); return EOK; } /** * Default implementation of the set_state method. Changes the internal * driver's state, calls the appropriate callback and notifies the NIL service * about this change. * * @param fun * @param state The new device's state * * @return EOK If the state was changed * @return EINVAL If the state cannot be changed */ int nic_set_state_impl(ddf_fun_t *fun, nic_device_state_t state) { if (state >= NIC_STATE_MAX) { return EINVAL; } nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_write_lock(&nic_data->main_lock); if (nic_data->state == state) { /* No change, nothing to do */ fibril_rwlock_write_unlock(&nic_data->main_lock); return EOK; } if (state == NIC_STATE_ACTIVE) { if (nic_data->client_session == NULL || nic_data->device_id < 0) { fibril_rwlock_write_unlock(&nic_data->main_lock); return EINVAL; } } state_change_handler event_handler = NULL; switch (state) { case NIC_STATE_STOPPED: event_handler = nic_data->on_stopping; break; case NIC_STATE_DOWN: event_handler = nic_data->on_going_down; break; case NIC_STATE_ACTIVE: event_handler = nic_data->on_activating; break; default: break; } if (event_handler != NULL) { int rc = event_handler(nic_data); if (rc != EOK) { fibril_rwlock_write_unlock(&nic_data->main_lock); return EINVAL; } } if (state == NIC_STATE_STOPPED) { /* Notify upper layers that we are reseting the MAC */ int rc = nic_ev_addr_changed(nic_data->client_session, nic_data->device_id, &nic_data->default_mac); nic_data->poll_mode = nic_data->default_poll_mode; memcpy(&nic_data->poll_period, &nic_data->default_poll_period, sizeof (struct timeval)); if (rc != EOK) { /* We have already ran the on stopped handler, even if we * terminated the state change we would end up in undefined state. * Therefore we just log the problem. */ } fibril_rwlock_write_lock(&nic_data->stats_lock); bzero(&nic_data->stats, sizeof (nic_device_stats_t)); fibril_rwlock_write_unlock(&nic_data->stats_lock); fibril_rwlock_write_lock(&nic_data->rxc_lock); nic_rxc_clear(&nic_data->rx_control); /* Reinsert device's default MAC */ nic_rxc_set_addr(&nic_data->rx_control, NULL, &nic_data->default_mac); fibril_rwlock_write_unlock(&nic_data->rxc_lock); memcpy(&nic_data->mac, &nic_data->default_mac, sizeof (nic_address_t)); fibril_rwlock_write_lock(&nic_data->wv_lock); nic_wol_virtues_clear(&nic_data->wol_virtues); fibril_rwlock_write_unlock(&nic_data->wv_lock); /* Ensure stopping period of NIC_POLL_SOFTWARE_PERIODIC */ nic_sw_period_stop(nic_data); } nic_data->state = state; nic_ev_device_state(nic_data->client_session, nic_data->device_id, state); fibril_rwlock_write_unlock(&nic_data->main_lock); return EOK; } /** * Default implementation of the send_frame method. * Send messages to the network. * * @param fun * @param data Frame data * @param size Frame size in bytes * * @return EOK If the message was sent * @return EBUSY If the device is not in state when the frame can be sent. */ int nic_send_frame_impl(ddf_fun_t *fun, void *data, size_t size) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->main_lock); if (nic_data->state != NIC_STATE_ACTIVE || nic_data->tx_busy) { fibril_rwlock_read_unlock(&nic_data->main_lock); return EBUSY; } nic_data->send_frame(nic_data, data, size); return EOK; } /** * Default implementation of the connect_client method. * Creates callback connection to the client. * * @param fun * @param device_id ID of the device as used in higher layers * * @return EOK On success, or negative error code. */ int nic_callback_create_impl(ddf_fun_t *fun, nic_device_id_t device_id) { nic_t *nic = (nic_t *) fun->driver_data; fibril_rwlock_write_lock(&nic->main_lock); nic->device_id = device_id; nic->client_session = async_callback_receive(EXCHANGE_SERIALIZE); if (nic->client_session == NULL) { fibril_rwlock_write_unlock(&nic->main_lock); return ENOMEM; } fibril_rwlock_write_unlock(&nic->main_lock); return EOK; } /** * Default implementation of the get_address method. * Retrieves the NIC's physical address. * * @param fun * @param address Pointer to the structure where the address will be stored. * * @return EOK If the services were bound * @return ELIMIT If the buffer is too short */ int nic_get_address_impl(ddf_fun_t *fun, nic_address_t *address) { assert(address); nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->main_lock); memcpy(address, &nic_data->mac, sizeof (nic_address_t)); fibril_rwlock_read_unlock(&nic_data->main_lock); return EOK; } /** * Default implementation of the get_stats method. Copies the statistics from * the drivers data to supplied buffer. * * @param fun * @param[out] stats The buffer for statistics * * @return EOK (cannot fail) */ int nic_get_stats_impl(ddf_fun_t *fun, nic_device_stats_t *stats) { nic_t *nic_data = (nic_t *) fun->driver_data; assert (stats != NULL); fibril_rwlock_read_lock(&nic_data->stats_lock); memcpy(stats, &nic_data->stats, sizeof (nic_device_stats_t)); fibril_rwlock_read_unlock(&nic_data->stats_lock); return EOK; } /** * Default implementation of unicast_get_mode method. * * @param fun * @param[out] mode Current operation mode * @param[in] max_count Max number of addresses that can be written into the * buffer (addr_list). * @param[out] addr_list Buffer for addresses * @param[out] addr_count Number of addresses written into the list * * @return EOK */ int nic_unicast_get_mode_impl(ddf_fun_t *fun, nic_unicast_mode_t *mode, size_t max_count, nic_address_t *addr_list, size_t *addr_count) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->rxc_lock); nic_rxc_unicast_get_mode(&nic_data->rx_control, mode, max_count, addr_list, addr_count); fibril_rwlock_read_unlock(&nic_data->rxc_lock); return EOK; } /** * Default implementation of unicast_set_mode method. * * @param fun * @param[in] mode New operation mode * @param[in] addr_list List of unicast addresses * @param[in] addr_count Number of addresses in the list * * @return EOK * @return EINVAL * @return ENOTSUP * @return ENOMEM */ int nic_unicast_set_mode_impl(ddf_fun_t *fun, nic_unicast_mode_t mode, const nic_address_t *addr_list, size_t addr_count) { assert((addr_count == 0 && addr_list == NULL) || (addr_count != 0 && addr_list != NULL)); size_t i; for (i = 0; i < addr_count; ++i) { if (addr_list[i].address[0] & 1) return EINVAL; } nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_write_lock(&nic_data->rxc_lock); int rc = ENOTSUP; if (nic_data->on_unicast_mode_change) { rc = nic_data->on_unicast_mode_change(nic_data, mode, addr_list, addr_count); } if (rc == EOK) { rc = nic_rxc_unicast_set_mode(&nic_data->rx_control, mode, addr_list, addr_count); /* After changing the mode the addr db gets cleared, therefore we have * to reinsert also the physical address of NIC. */ nic_rxc_set_addr(&nic_data->rx_control, NULL, &nic_data->mac); } fibril_rwlock_write_unlock(&nic_data->rxc_lock); return rc; } /** * Default implementation of multicast_get_mode method. * * @param fun * @param[out] mode Current operation mode * @param[in] max_count Max number of addresses that can be written into the * buffer (addr_list). * @param[out] addr_list Buffer for addresses * @param[out] addr_count Number of addresses written into the list * * @return EOK */ int nic_multicast_get_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t *mode, size_t max_count, nic_address_t *addr_list, size_t *addr_count) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->rxc_lock); nic_rxc_multicast_get_mode(&nic_data->rx_control, mode, max_count, addr_list, addr_count); fibril_rwlock_read_unlock(&nic_data->rxc_lock); return EOK; } /** * Default implementation of multicast_set_mode method. * * @param fun * @param[in] mode New operation mode * @param[in] addr_list List of multicast addresses * @param[in] addr_count Number of addresses in the list * * @return EOK * @return EINVAL * @return ENOTSUP * @return ENOMEM */ int nic_multicast_set_mode_impl(ddf_fun_t *fun, nic_multicast_mode_t mode, const nic_address_t *addr_list, size_t addr_count) { assert((addr_count == 0 && addr_list == NULL) || (addr_count != 0 && addr_list != NULL)); size_t i; for (i = 0; i < addr_count; ++i) { if (!(addr_list[i].address[0] & 1)) return EINVAL; } nic_t *nic_data = (nic_t *) fun->dev->driver_data; fibril_rwlock_write_lock(&nic_data->rxc_lock); int rc = ENOTSUP; if (nic_data->on_multicast_mode_change) { rc = nic_data->on_multicast_mode_change(nic_data, mode, addr_list, addr_count); } if (rc == EOK) { rc = nic_rxc_multicast_set_mode(&nic_data->rx_control, mode, addr_list, addr_count); } fibril_rwlock_write_unlock(&nic_data->rxc_lock); return rc; } /** * Default implementation of broadcast_get_mode method. * * @param fun * @param[out] mode Current operation mode * * @return EOK */ int nic_broadcast_get_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t *mode) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->rxc_lock); nic_rxc_broadcast_get_mode(&nic_data->rx_control, mode); fibril_rwlock_read_unlock(&nic_data->rxc_lock); return EOK; } /** * Default implementation of broadcast_set_mode method. * * @param fun * @param[in] mode New operation mode * * @return EOK * @return EINVAL * @return ENOTSUP * @return ENOMEM */ int nic_broadcast_set_mode_impl(ddf_fun_t *fun, nic_broadcast_mode_t mode) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_write_lock(&nic_data->rxc_lock); int rc = ENOTSUP; if (nic_data->on_broadcast_mode_change) { rc = nic_data->on_broadcast_mode_change(nic_data, mode); } if (rc == EOK) { rc = nic_rxc_broadcast_set_mode(&nic_data->rx_control, mode); } fibril_rwlock_write_unlock(&nic_data->rxc_lock); return rc; } /** * Default implementation of blocked_sources_get method. * * @param fun * @param[in] max_count Max number of addresses that can be written into the * buffer (addr_list). * @param[out] addr_list Buffer for addresses * @param[out] addr_count Number of addresses written into the list * * @return EOK */ int nic_blocked_sources_get_impl(ddf_fun_t *fun, size_t max_count, nic_address_t *addr_list, size_t *addr_count) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->rxc_lock); nic_rxc_blocked_sources_get(&nic_data->rx_control, max_count, addr_list, addr_count); fibril_rwlock_read_unlock(&nic_data->rxc_lock); return EOK; } /** * Default implementation of blocked_sources_set method. * * @param fun * @param[in] addr_list List of blocked addresses * @param[in] addr_count Number of addresses in the list * * @return EOK * @return EINVAL * @return ENOTSUP * @return ENOMEM */ int nic_blocked_sources_set_impl(ddf_fun_t *fun, const nic_address_t *addr_list, size_t addr_count) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_write_lock(&nic_data->rxc_lock); if (nic_data->on_blocked_sources_change) { nic_data->on_blocked_sources_change(nic_data, addr_list, addr_count); } int rc = nic_rxc_blocked_sources_set(&nic_data->rx_control, addr_list, addr_count); fibril_rwlock_write_unlock(&nic_data->rxc_lock); return rc; } /** * Default implementation of vlan_get_mask method. * * @param fun * @param[out] mask Current VLAN mask * * @return EOK * @return ENOENT If the mask is not set */ int nic_vlan_get_mask_impl(ddf_fun_t *fun, nic_vlan_mask_t *mask) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->rxc_lock); int rc = nic_rxc_vlan_get_mask(&nic_data->rx_control, mask); fibril_rwlock_read_unlock(&nic_data->rxc_lock); return rc; } /** * Default implementation of vlan_set_mask method. * * @param fun * @param[in] mask The new VLAN mask * * @return EOK * @return ENOMEM */ int nic_vlan_set_mask_impl(ddf_fun_t *fun, const nic_vlan_mask_t *mask) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_write_lock(&nic_data->rxc_lock); int rc = nic_rxc_vlan_set_mask(&nic_data->rx_control, mask); if (rc == EOK && nic_data->on_vlan_mask_change) { nic_data->on_vlan_mask_change(nic_data, mask); } fibril_rwlock_write_unlock(&nic_data->rxc_lock); return rc; } /** * Default implementation of the wol_virtue_add method. * Create a new WOL virtue. * * @param[in] fun * @param[in] type Type of the virtue * @param[in] data Data required for this virtue (depends on type) * @param[in] length Length of the data * @param[out] filter Identifier of the new virtue * * @return EOK If the operation was successfully completed * @return EINVAL If virtue type is not supported or the data are invalid * @return ELIMIT If the driver does not allow to create more virtues * @return ENOMEM If there was not enough memory to complete the operation */ int nic_wol_virtue_add_impl(ddf_fun_t *fun, nic_wv_type_t type, const void *data, size_t length, nic_wv_id_t *new_id) { nic_t *nic_data = (nic_t *) fun->driver_data; if (nic_data->on_wol_virtue_add == NULL || nic_data->on_wol_virtue_remove == NULL) { return ENOTSUP; } if (type == NIC_WV_NONE || type >= NIC_WV_MAX) { return EINVAL; } if (nic_wol_virtues_verify(type, data, length) != EOK) { return EINVAL; } nic_wol_virtue_t *virtue = malloc(sizeof (nic_wol_virtue_t)); if (virtue == NULL) { return ENOMEM; } bzero(virtue, sizeof (nic_wol_virtue_t)); if (length != 0) { virtue->data = malloc(length); if (virtue->data == NULL) { free(virtue); return ENOMEM; } memcpy((void *) virtue->data, data, length); } virtue->type = type; virtue->length = length; fibril_rwlock_write_lock(&nic_data->wv_lock); /* Check if we haven't reached the maximum */ if (nic_data->wol_virtues.caps_max[type] < 0) { fibril_rwlock_write_unlock(&nic_data->wv_lock); return EINVAL; } if ((int) nic_data->wol_virtues.lists_sizes[type] >= nic_data->wol_virtues.caps_max[type]) { fibril_rwlock_write_unlock(&nic_data->wv_lock); return ELIMIT; } /* Call the user-defined add callback */ int rc = nic_data->on_wol_virtue_add(nic_data, virtue); if (rc != EOK) { free(virtue->data); free(virtue); fibril_rwlock_write_unlock(&nic_data->wv_lock); return rc; } rc = nic_wol_virtues_add(&nic_data->wol_virtues, virtue); if (rc != EOK) { /* If the adding fails, call user-defined remove callback */ nic_data->on_wol_virtue_remove(nic_data, virtue); fibril_rwlock_write_unlock(&nic_data->wv_lock); free(virtue->data); free(virtue); return rc; } else { *new_id = virtue->id; fibril_rwlock_write_unlock(&nic_data->wv_lock); } return EOK; } /** * Default implementation of the wol_virtue_remove method. * Destroys the WOL virtue. * * @param[in] fun * @param[in] id WOL virtue identification * * @return EOK If the operation was successfully completed * @return ENOTSUP If the function is not supported by the driver or device * @return ENOENT If the virtue identifier is not valid. */ int nic_wol_virtue_remove_impl(ddf_fun_t *fun, nic_wv_id_t id) { nic_t *nic_data = (nic_t *) fun->driver_data; if (nic_data->on_wol_virtue_add == NULL || nic_data->on_wol_virtue_remove == NULL) { return ENOTSUP; } fibril_rwlock_write_lock(&nic_data->wv_lock); nic_wol_virtue_t *virtue = nic_wol_virtues_remove(&nic_data->wol_virtues, id); if (virtue == NULL) { fibril_rwlock_write_unlock(&nic_data->wv_lock); return ENOENT; } /* The event handler is called after the filter was removed */ nic_data->on_wol_virtue_remove(nic_data, virtue); fibril_rwlock_write_unlock(&nic_data->wv_lock); free(virtue->data); free(virtue); return EOK; } /** * Default implementation of the wol_virtue_probe method. * Queries the type and data of the virtue. * * @param[in] fun * @param[in] id Virtue identifier * @param[out] type Type of the virtue. Can be NULL. * @param[out] data Data used when the virtue was created. Can be NULL. * @param[out] length Length of the data. Can be NULL. * * @return EOK If the operation was successfully completed * @return ENOENT If the virtue identifier is not valid. * @return ENOMEM If there was not enough memory to complete the operation */ int nic_wol_virtue_probe_impl(ddf_fun_t *fun, nic_wv_id_t id, nic_wv_type_t *type, size_t max_length, void *data, size_t *length) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->wv_lock); const nic_wol_virtue_t *virtue = nic_wol_virtues_find(&nic_data->wol_virtues, id); if (virtue == NULL) { *type = NIC_WV_NONE; *length = 0; fibril_rwlock_read_unlock(&nic_data->wv_lock); return ENOENT; } else { *type = virtue->type; if (max_length > virtue->length) { max_length = virtue->length; } memcpy(data, virtue->data, max_length); *length = virtue->length; fibril_rwlock_read_unlock(&nic_data->wv_lock); return EOK; } } /** * Default implementation of the wol_virtue_list method. * List filters of the specified type. If NIC_WV_NONE is the type, it lists all * filters. * * @param[in] fun * @param[in] type Type of the virtues * @param[out] virtues Vector of virtue ID's. * @param[out] count Length of the data. Can be NULL. * * @return EOK If the operation was successfully completed * @return ENOENT If the filter identification is not valid. * @return ENOMEM If there was not enough memory to complete the operation */ int nic_wol_virtue_list_impl(ddf_fun_t *fun, nic_wv_type_t type, size_t max_count, nic_wv_id_t *id_list, size_t *id_count) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->wv_lock); int rc = nic_wol_virtues_list(&nic_data->wol_virtues, type, max_count, id_list, id_count); fibril_rwlock_read_unlock(&nic_data->wv_lock); return rc; } /** * Default implementation of the wol_virtue_get_caps method. * Queries for the current capabilities for some type of filter. * * @param[in] fun * @param[in] type Type of the virtues * @param[out] count Number of virtues of this type that can be currently set * * @return EOK If the operation was successfully completed */ int nic_wol_virtue_get_caps_impl(ddf_fun_t *fun, nic_wv_type_t type, int *count) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->wv_lock); *count = nic_data->wol_virtues.caps_max[type] - (int) nic_data->wol_virtues.lists_sizes[type]; fibril_rwlock_read_unlock(&nic_data->wv_lock); return EOK; } /** * Default implementation of the poll_get_mode method. * Queries the current interrupt/poll mode of the NIC * * @param[in] fun * @param[out] mode Current poll mode * @param[out] period Period used in periodic polling. Can be NULL. * * @return EOK If the operation was successfully completed * @return ENOTSUP This function is not supported. * @return EPARTY Error in communication protocol */ int nic_poll_get_mode_impl(ddf_fun_t *fun, nic_poll_mode_t *mode, struct timeval *period) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->main_lock); *mode = nic_data->poll_mode; memcpy(period, &nic_data->poll_period, sizeof (struct timeval)); fibril_rwlock_read_unlock(&nic_data->main_lock); return EOK; } /** * Default implementation of the poll_set_mode_impl method. * Sets the interrupt/poll mode of the NIC. * * @param[in] fun * @param[in] mode The new poll mode * @param[in] period Period used in periodic polling. Can be NULL. * * @return EOK If the operation was successfully completed * @return ENOTSUP This operation is not supported. * @return EPARTY Error in communication protocol */ int nic_poll_set_mode_impl(ddf_fun_t *fun, nic_poll_mode_t mode, const struct timeval *period) { nic_t *nic_data = (nic_t *) fun->driver_data; /* If the driver does not implement the poll mode change handler it cannot * switch off interrupts and this is not supported. */ if (nic_data->on_poll_mode_change == NULL) return ENOTSUP; if ((mode == NIC_POLL_ON_DEMAND) && nic_data->on_poll_request == NULL) return ENOTSUP; if (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) { if (period == NULL) return EINVAL; if (period->tv_sec == 0 && period->tv_usec == 0) return EINVAL; if (period->tv_sec < 0 || period->tv_usec < 0) return EINVAL; } fibril_rwlock_write_lock(&nic_data->main_lock); int rc = nic_data->on_poll_mode_change(nic_data, mode, period); assert(rc == EOK || rc == ENOTSUP || rc == EINVAL); if (rc == ENOTSUP && (nic_data->on_poll_request != NULL) && (mode == NIC_POLL_PERIODIC || mode == NIC_POLL_SOFTWARE_PERIODIC) ) { rc = nic_data->on_poll_mode_change(nic_data, NIC_POLL_ON_DEMAND, NULL); assert(rc == EOK || rc == ENOTSUP); if (rc == EOK) nic_sw_period_start(nic_data); } if (rc == EOK) { nic_data->poll_mode = mode; if (period) nic_data->poll_period = *period; } fibril_rwlock_write_unlock(&nic_data->main_lock); return rc; } /** * Default implementation of the poll_now method. * Wrapper for the actual poll implementation. * * @param[in] fun * * @return EOK If the NIC was polled * @return ENOTSUP If the function is not supported * @return EINVAL If the NIC is not in state where it allows on demand polling */ int nic_poll_now_impl(ddf_fun_t *fun) { nic_t *nic_data = (nic_t *) fun->driver_data; fibril_rwlock_read_lock(&nic_data->main_lock); if (nic_data->poll_mode != NIC_POLL_ON_DEMAND) { fibril_rwlock_read_unlock(&nic_data->main_lock); return EINVAL; } if (nic_data->on_poll_request != NULL) { nic_data->on_poll_request(nic_data); fibril_rwlock_read_unlock(&nic_data->main_lock); return EOK; } else { fibril_rwlock_read_unlock(&nic_data->main_lock); return ENOTSUP; } } /** * Default handler for unknown methods (outside of the NIC interface). * Logs a warning message and returns ENOTSUP to the caller. * * @param fun The DDF function where the method should be called. * @param callid IPC call identifier * @param call IPC call data */ void nic_default_handler_impl(ddf_fun_t *fun, ipc_callid_t callid, ipc_call_t *call) { async_answer_0(callid, ENOTSUP); } /** * Default (empty) OPEN function implementation. * * @param fun The DDF function * * @return EOK always. */ int nic_open_impl(ddf_fun_t *fun) { return EOK; } /** * Default (empty) OPEN function implementation. * * @param fun The DDF function */ void nic_close_impl(ddf_fun_t *fun) { } /** @} */