You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

196 lines
6.0 KiB

/*
* Copyright (C) 2015 Freie Universität Berlin
* 2015 Kaspar Schleiser <kaspar@schleiser.de>
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup net
* @file
* @brief Glue for netdev2 devices to netapi
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Kaspar Schleiser <kaspar@schleiser.de>
* @}
*/
#include <errno.h>
#include "kernel.h"
#include "msg.h"
#include "thread.h"
#include "net/gnrc.h"
#include "net/gnrc/nettype.h"
#include "net/netdev2.h"
#include "net/gnrc/netdev2.h"
#include "net/ethernet/hdr.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
#if defined(MODULE_OD) && ENABLE_DEBUG
#include "od.h"
#endif
#define NETDEV2_NETAPI_MSG_QUEUE_SIZE 8
static void _pass_on_packet(gnrc_pktsnip_t *pkt);
/**
* @brief Function called by the device driver on device events
*
* @param[in] event type of event
* @param[in] data optional parameter
*/
static void _event_cb(netdev2_t *dev, netdev2_event_t event, void *data)
{
(void) data;
gnrc_netdev2_t *gnrc_netdev2 = (gnrc_netdev2_t*) dev->isr_arg;
if (event == NETDEV2_EVENT_ISR) {
msg_t msg;
msg.type = NETDEV2_MSG_TYPE_EVENT;
msg.content.ptr = (void*) gnrc_netdev2;
if (msg_send(&msg, gnrc_netdev2->pid) <= 0) {
puts("gnrc_netdev2: possibly lost interrupt.");
}
}
else {
DEBUG("gnrc_netdev2: event triggered -> %i\n", event);
switch(event) {
case NETDEV2_EVENT_RX_COMPLETE:
{
gnrc_pktsnip_t *pkt = gnrc_netdev2->recv(gnrc_netdev2);
if (pkt) {
_pass_on_packet(pkt);
}
break;
}
default:
DEBUG("gnrc_netdev2: warning: unhandled event %u.\n", event);
}
}
}
static void _pass_on_packet(gnrc_pktsnip_t *pkt)
{
/* throw away packet if no one is interested */
if (!gnrc_netapi_dispatch_receive(pkt->type, GNRC_NETREG_DEMUX_CTX_ALL, pkt)) {
DEBUG("gnrc_netdev2: unable to forward packet of type %i\n", pkt->type);
gnrc_pktbuf_release(pkt);
return;
}
}
/**
* @brief Startup code and event loop of the gnrc_netdev2 layer
*
* @param[in] args expects a pointer to the underlying netdev device
*
* @return never returns
*/
static void *_gnrc_netdev2_thread(void *args)
{
DEBUG("gnrc_netdev2: starting thread\n");
gnrc_netdev2_t *gnrc_netdev2 = (gnrc_netdev2_t*) args;
netdev2_t *dev = gnrc_netdev2->dev;
gnrc_netdev2->pid = thread_getpid();
gnrc_netapi_opt_t *opt;
int res;
msg_t msg, reply, msg_queue[NETDEV2_NETAPI_MSG_QUEUE_SIZE];
/* setup the MAC layers message queue */
msg_init_queue(msg_queue, NETDEV2_NETAPI_MSG_QUEUE_SIZE);
/* register the event callback with the device driver */
dev->event_callback = _event_cb;
dev->isr_arg = (void*) gnrc_netdev2;
/* register the device to the network stack*/
gnrc_netif_add(thread_getpid());
/* initialize low-level driver */
dev->driver->init(dev);
/* start the event loop */
while (1) {
DEBUG("gnrc_netdev2: waiting for incoming messages\n");
msg_receive(&msg);
/* dispatch NETDEV and NETAPI messages */
switch (msg.type) {
case NETDEV2_MSG_TYPE_EVENT:
DEBUG("gnrc_netdev2: GNRC_NETDEV_MSG_TYPE_EVENT received\n");
dev->driver->isr(dev);
break;
case GNRC_NETAPI_MSG_TYPE_SND:
DEBUG("gnrc_netdev2: GNRC_NETAPI_MSG_TYPE_SND received\n");
gnrc_pktsnip_t *pkt = (gnrc_pktsnip_t *)msg.content.ptr;
gnrc_netdev2->send(gnrc_netdev2, pkt);
break;
case GNRC_NETAPI_MSG_TYPE_SET:
/* read incoming options */
opt = (gnrc_netapi_opt_t *)msg.content.ptr;
DEBUG("gnrc_netdev2: GNRC_NETAPI_MSG_TYPE_SET received. opt=%s\n",
netopt2str(opt->opt));
/* set option for device driver */
res = dev->driver->set(dev, opt->opt, opt->data, opt->data_len);
DEBUG("gnrc_netdev2: response of netdev->set: %i\n", res);
/* send reply to calling thread */
reply.type = GNRC_NETAPI_MSG_TYPE_ACK;
reply.content.value = (uint32_t)res;
msg_reply(&msg, &reply);
break;
case GNRC_NETAPI_MSG_TYPE_GET:
/* read incoming options */
opt = (gnrc_netapi_opt_t *)msg.content.ptr;
DEBUG("gnrc_netdev2: GNRC_NETAPI_MSG_TYPE_GET received. opt=%s\n",
netopt2str(opt->opt));
/* get option from device driver */
res = dev->driver->get(dev, opt->opt, opt->data, opt->data_len);
DEBUG("gnrc_netdev2: response of netdev->get: %i\n", res);
/* send reply to calling thread */
reply.type = GNRC_NETAPI_MSG_TYPE_ACK;
reply.content.value = (uint32_t)res;
msg_reply(&msg, &reply);
break;
default:
DEBUG("gnrc_netdev2: Unknown command %" PRIu16 "\n", msg.type);
break;
}
}
/* never reached */
return NULL;
}
kernel_pid_t gnrc_netdev2_init(char *stack, int stacksize, char priority,
const char *name, gnrc_netdev2_t *gnrc_netdev2)
{
kernel_pid_t res;
/* check if given netdev device is defined and the driver is set */
if (gnrc_netdev2 == NULL || gnrc_netdev2->dev == NULL) {
return -ENODEV;
}
/* create new gnrc_netdev2 thread */
res = thread_create(stack, stacksize, priority, THREAD_CREATE_STACKTEST,
_gnrc_netdev2_thread, (void *)gnrc_netdev2, name);
if (res <= 0) {
return -EINVAL;
}
return res;
}