CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2
Fork of USB_Ethernet by
stack/pico_device.c@2:540f6e142d59, 2013-08-03 (annotated)
- Committer:
- daniele
- Date:
- Sat Aug 03 13:16:14 2013 +0000
- Revision:
- 2:540f6e142d59
Moved to single package
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
daniele | 2:540f6e142d59 | 1 | /********************************************************************* |
daniele | 2:540f6e142d59 | 2 | PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. |
daniele | 2:540f6e142d59 | 3 | See LICENSE and COPYING for usage. |
daniele | 2:540f6e142d59 | 4 | |
daniele | 2:540f6e142d59 | 5 | . |
daniele | 2:540f6e142d59 | 6 | |
daniele | 2:540f6e142d59 | 7 | Authors: Daniele Lacamera |
daniele | 2:540f6e142d59 | 8 | *********************************************************************/ |
daniele | 2:540f6e142d59 | 9 | |
daniele | 2:540f6e142d59 | 10 | |
daniele | 2:540f6e142d59 | 11 | #include "pico_config.h" |
daniele | 2:540f6e142d59 | 12 | #include "pico_device.h" |
daniele | 2:540f6e142d59 | 13 | #include "pico_stack.h" |
daniele | 2:540f6e142d59 | 14 | #include "pico_protocol.h" |
daniele | 2:540f6e142d59 | 15 | #include "pico_tree.h" |
daniele | 2:540f6e142d59 | 16 | |
daniele | 2:540f6e142d59 | 17 | |
daniele | 2:540f6e142d59 | 18 | static int pico_dev_cmp(void *ka, void *kb) |
daniele | 2:540f6e142d59 | 19 | { |
daniele | 2:540f6e142d59 | 20 | struct pico_device *a = ka, *b = kb; |
daniele | 2:540f6e142d59 | 21 | if (a->hash < b->hash) |
daniele | 2:540f6e142d59 | 22 | return -1; |
daniele | 2:540f6e142d59 | 23 | if (a->hash > b->hash) |
daniele | 2:540f6e142d59 | 24 | return 1; |
daniele | 2:540f6e142d59 | 25 | return 0; |
daniele | 2:540f6e142d59 | 26 | } |
daniele | 2:540f6e142d59 | 27 | |
daniele | 2:540f6e142d59 | 28 | PICO_TREE_DECLARE(Device_tree,pico_dev_cmp); |
daniele | 2:540f6e142d59 | 29 | |
daniele | 2:540f6e142d59 | 30 | int pico_device_init(struct pico_device *dev, char *name, uint8_t *mac) |
daniele | 2:540f6e142d59 | 31 | { |
daniele | 2:540f6e142d59 | 32 | int len = strlen(name); |
daniele | 2:540f6e142d59 | 33 | if(len>MAX_DEVICE_NAME) |
daniele | 2:540f6e142d59 | 34 | len = MAX_DEVICE_NAME; |
daniele | 2:540f6e142d59 | 35 | memcpy(dev->name, name, len); |
daniele | 2:540f6e142d59 | 36 | dev->hash = pico_hash(dev->name); |
daniele | 2:540f6e142d59 | 37 | |
daniele | 2:540f6e142d59 | 38 | pico_tree_insert(&Device_tree,dev); |
daniele | 2:540f6e142d59 | 39 | dev->q_in = pico_zalloc(sizeof(struct pico_queue)); |
daniele | 2:540f6e142d59 | 40 | dev->q_out = pico_zalloc(sizeof(struct pico_queue)); |
daniele | 2:540f6e142d59 | 41 | |
daniele | 2:540f6e142d59 | 42 | if (mac) { |
daniele | 2:540f6e142d59 | 43 | dev->eth = pico_zalloc(sizeof(struct pico_ethdev)); |
daniele | 2:540f6e142d59 | 44 | memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH); |
daniele | 2:540f6e142d59 | 45 | } else { |
daniele | 2:540f6e142d59 | 46 | dev->eth = NULL; |
daniele | 2:540f6e142d59 | 47 | } |
daniele | 2:540f6e142d59 | 48 | |
daniele | 2:540f6e142d59 | 49 | if (!dev->q_in || !dev->q_out || (mac && !dev->eth)) |
daniele | 2:540f6e142d59 | 50 | return -1; |
daniele | 2:540f6e142d59 | 51 | return 0; |
daniele | 2:540f6e142d59 | 52 | } |
daniele | 2:540f6e142d59 | 53 | |
daniele | 2:540f6e142d59 | 54 | void pico_device_destroy(struct pico_device *dev) |
daniele | 2:540f6e142d59 | 55 | { |
daniele | 2:540f6e142d59 | 56 | if (dev->destroy) |
daniele | 2:540f6e142d59 | 57 | dev->destroy(dev); |
daniele | 2:540f6e142d59 | 58 | |
daniele | 2:540f6e142d59 | 59 | if (dev->q_in) { |
daniele | 2:540f6e142d59 | 60 | pico_queue_empty(dev->q_in); |
daniele | 2:540f6e142d59 | 61 | pico_free(dev->q_in); |
daniele | 2:540f6e142d59 | 62 | } |
daniele | 2:540f6e142d59 | 63 | if (dev->q_out) { |
daniele | 2:540f6e142d59 | 64 | pico_queue_empty(dev->q_out); |
daniele | 2:540f6e142d59 | 65 | pico_free(dev->q_out); |
daniele | 2:540f6e142d59 | 66 | } |
daniele | 2:540f6e142d59 | 67 | |
daniele | 2:540f6e142d59 | 68 | if (dev->eth) |
daniele | 2:540f6e142d59 | 69 | pico_free(dev->eth); |
daniele | 2:540f6e142d59 | 70 | |
daniele | 2:540f6e142d59 | 71 | pico_tree_delete(&Device_tree,dev); |
daniele | 2:540f6e142d59 | 72 | pico_free(dev); |
daniele | 2:540f6e142d59 | 73 | } |
daniele | 2:540f6e142d59 | 74 | |
daniele | 2:540f6e142d59 | 75 | static int devloop(struct pico_device *dev, int loop_score, int direction) |
daniele | 2:540f6e142d59 | 76 | { |
daniele | 2:540f6e142d59 | 77 | struct pico_frame *f; |
daniele | 2:540f6e142d59 | 78 | |
daniele | 2:540f6e142d59 | 79 | /* If device supports interrupts, read the value of the condition and trigger the dsr */ |
daniele | 2:540f6e142d59 | 80 | if ((dev->__serving_interrupt) && (dev->dsr)) { |
daniele | 2:540f6e142d59 | 81 | /* call dsr routine */ |
daniele | 2:540f6e142d59 | 82 | loop_score = dev->dsr(dev, loop_score); |
daniele | 2:540f6e142d59 | 83 | } |
daniele | 2:540f6e142d59 | 84 | |
daniele | 2:540f6e142d59 | 85 | /* If device supports polling, give control. Loop score is managed internally, |
daniele | 2:540f6e142d59 | 86 | * remaining loop points are returned. */ |
daniele | 2:540f6e142d59 | 87 | if (dev->poll) { |
daniele | 2:540f6e142d59 | 88 | loop_score = dev->poll(dev, loop_score); |
daniele | 2:540f6e142d59 | 89 | } |
daniele | 2:540f6e142d59 | 90 | |
daniele | 2:540f6e142d59 | 91 | if (direction == PICO_LOOP_DIR_OUT) { |
daniele | 2:540f6e142d59 | 92 | |
daniele | 2:540f6e142d59 | 93 | while(loop_score > 0) { |
daniele | 2:540f6e142d59 | 94 | if (dev->q_out->frames <= 0) |
daniele | 2:540f6e142d59 | 95 | break; |
daniele | 2:540f6e142d59 | 96 | |
daniele | 2:540f6e142d59 | 97 | /* Device dequeue + send */ |
daniele | 2:540f6e142d59 | 98 | f = pico_dequeue(dev->q_out); |
daniele | 2:540f6e142d59 | 99 | if (f) { |
daniele | 2:540f6e142d59 | 100 | if (dev->eth) { |
daniele | 2:540f6e142d59 | 101 | int ret = pico_ethernet_send(f); |
daniele | 2:540f6e142d59 | 102 | if (0 == ret) { |
daniele | 2:540f6e142d59 | 103 | loop_score--; |
daniele | 2:540f6e142d59 | 104 | continue; |
daniele | 2:540f6e142d59 | 105 | } if (ret < 0) { |
daniele | 2:540f6e142d59 | 106 | if (!pico_source_is_local(f)) { |
daniele | 2:540f6e142d59 | 107 | dbg("Destination unreachable -------> SEND ICMP\n"); |
daniele | 2:540f6e142d59 | 108 | pico_notify_dest_unreachable(f); |
daniele | 2:540f6e142d59 | 109 | } else { |
daniele | 2:540f6e142d59 | 110 | dbg("Destination unreachable -------> LOCAL\n"); |
daniele | 2:540f6e142d59 | 111 | } |
daniele | 2:540f6e142d59 | 112 | pico_frame_discard(f); |
daniele | 2:540f6e142d59 | 113 | continue; |
daniele | 2:540f6e142d59 | 114 | } |
daniele | 2:540f6e142d59 | 115 | } else { |
daniele | 2:540f6e142d59 | 116 | dev->send(dev, f->start, f->len); |
daniele | 2:540f6e142d59 | 117 | } |
daniele | 2:540f6e142d59 | 118 | pico_frame_discard(f); |
daniele | 2:540f6e142d59 | 119 | loop_score--; |
daniele | 2:540f6e142d59 | 120 | } |
daniele | 2:540f6e142d59 | 121 | } |
daniele | 2:540f6e142d59 | 122 | |
daniele | 2:540f6e142d59 | 123 | } else if (direction == PICO_LOOP_DIR_IN) { |
daniele | 2:540f6e142d59 | 124 | |
daniele | 2:540f6e142d59 | 125 | while(loop_score > 0) { |
daniele | 2:540f6e142d59 | 126 | if (dev->q_in->frames <= 0) |
daniele | 2:540f6e142d59 | 127 | break; |
daniele | 2:540f6e142d59 | 128 | |
daniele | 2:540f6e142d59 | 129 | /* Receive */ |
daniele | 2:540f6e142d59 | 130 | f = pico_dequeue(dev->q_in); |
daniele | 2:540f6e142d59 | 131 | if (f) { |
daniele | 2:540f6e142d59 | 132 | if (dev->eth) { |
daniele | 2:540f6e142d59 | 133 | f->datalink_hdr = f->buffer; |
daniele | 2:540f6e142d59 | 134 | pico_ethernet_receive(f); |
daniele | 2:540f6e142d59 | 135 | } else { |
daniele | 2:540f6e142d59 | 136 | f->net_hdr = f->buffer; |
daniele | 2:540f6e142d59 | 137 | pico_network_receive(f); |
daniele | 2:540f6e142d59 | 138 | } |
daniele | 2:540f6e142d59 | 139 | loop_score--; |
daniele | 2:540f6e142d59 | 140 | } |
daniele | 2:540f6e142d59 | 141 | } |
daniele | 2:540f6e142d59 | 142 | } |
daniele | 2:540f6e142d59 | 143 | |
daniele | 2:540f6e142d59 | 144 | return loop_score; |
daniele | 2:540f6e142d59 | 145 | } |
daniele | 2:540f6e142d59 | 146 | |
daniele | 2:540f6e142d59 | 147 | |
daniele | 2:540f6e142d59 | 148 | #define DEV_LOOP_MIN 16 |
daniele | 2:540f6e142d59 | 149 | |
daniele | 2:540f6e142d59 | 150 | int pico_devices_loop(int loop_score, int direction) |
daniele | 2:540f6e142d59 | 151 | { |
daniele | 2:540f6e142d59 | 152 | struct pico_device *start; |
daniele | 2:540f6e142d59 | 153 | static struct pico_device *next = NULL, *next_in = NULL, *next_out = NULL; |
daniele | 2:540f6e142d59 | 154 | static struct pico_tree_node * next_node, * in_node, * out_node; |
daniele | 2:540f6e142d59 | 155 | |
daniele | 2:540f6e142d59 | 156 | if (next_in == NULL) { |
daniele | 2:540f6e142d59 | 157 | in_node = pico_tree_firstNode(Device_tree.root); |
daniele | 2:540f6e142d59 | 158 | next_in = in_node->keyValue; |
daniele | 2:540f6e142d59 | 159 | } |
daniele | 2:540f6e142d59 | 160 | if (next_out == NULL) { |
daniele | 2:540f6e142d59 | 161 | out_node = pico_tree_firstNode(Device_tree.root); |
daniele | 2:540f6e142d59 | 162 | next_out = out_node->keyValue; |
daniele | 2:540f6e142d59 | 163 | } |
daniele | 2:540f6e142d59 | 164 | |
daniele | 2:540f6e142d59 | 165 | if (direction == PICO_LOOP_DIR_IN) |
daniele | 2:540f6e142d59 | 166 | { |
daniele | 2:540f6e142d59 | 167 | next_node = in_node; |
daniele | 2:540f6e142d59 | 168 | next = next_in; |
daniele | 2:540f6e142d59 | 169 | } |
daniele | 2:540f6e142d59 | 170 | else if (direction == PICO_LOOP_DIR_OUT) |
daniele | 2:540f6e142d59 | 171 | { |
daniele | 2:540f6e142d59 | 172 | next_node = out_node; |
daniele | 2:540f6e142d59 | 173 | next = next_out; |
daniele | 2:540f6e142d59 | 174 | } |
daniele | 2:540f6e142d59 | 175 | |
daniele | 2:540f6e142d59 | 176 | /* init start node */ |
daniele | 2:540f6e142d59 | 177 | start = next; |
daniele | 2:540f6e142d59 | 178 | |
daniele | 2:540f6e142d59 | 179 | /* round-robin all devices, break if traversed all devices */ |
daniele | 2:540f6e142d59 | 180 | while (loop_score > DEV_LOOP_MIN && next != NULL) { |
daniele | 2:540f6e142d59 | 181 | loop_score = devloop(next, loop_score, direction); |
daniele | 2:540f6e142d59 | 182 | |
daniele | 2:540f6e142d59 | 183 | next_node = pico_tree_next(next_node); |
daniele | 2:540f6e142d59 | 184 | next = next_node->keyValue; |
daniele | 2:540f6e142d59 | 185 | |
daniele | 2:540f6e142d59 | 186 | if (next == NULL) |
daniele | 2:540f6e142d59 | 187 | { |
daniele | 2:540f6e142d59 | 188 | next_node = pico_tree_firstNode(Device_tree.root); |
daniele | 2:540f6e142d59 | 189 | next = next_node->keyValue; |
daniele | 2:540f6e142d59 | 190 | } |
daniele | 2:540f6e142d59 | 191 | if (next == start) |
daniele | 2:540f6e142d59 | 192 | break; |
daniele | 2:540f6e142d59 | 193 | } |
daniele | 2:540f6e142d59 | 194 | |
daniele | 2:540f6e142d59 | 195 | if (direction == PICO_LOOP_DIR_IN) |
daniele | 2:540f6e142d59 | 196 | { |
daniele | 2:540f6e142d59 | 197 | in_node = next_node; |
daniele | 2:540f6e142d59 | 198 | next_in = next; |
daniele | 2:540f6e142d59 | 199 | } |
daniele | 2:540f6e142d59 | 200 | else if (direction == PICO_LOOP_DIR_OUT) |
daniele | 2:540f6e142d59 | 201 | { |
daniele | 2:540f6e142d59 | 202 | out_node = next_node; |
daniele | 2:540f6e142d59 | 203 | next_out = next; |
daniele | 2:540f6e142d59 | 204 | } |
daniele | 2:540f6e142d59 | 205 | |
daniele | 2:540f6e142d59 | 206 | return loop_score; |
daniele | 2:540f6e142d59 | 207 | } |
daniele | 2:540f6e142d59 | 208 | |
daniele | 2:540f6e142d59 | 209 | struct pico_device* pico_get_device(char* name) |
daniele | 2:540f6e142d59 | 210 | { |
daniele | 2:540f6e142d59 | 211 | struct pico_device *dev; |
daniele | 2:540f6e142d59 | 212 | struct pico_tree_node * index; |
daniele | 2:540f6e142d59 | 213 | pico_tree_foreach(index, &Device_tree){ |
daniele | 2:540f6e142d59 | 214 | dev = index->keyValue; |
daniele | 2:540f6e142d59 | 215 | if(strcmp(name, dev->name) == 0) |
daniele | 2:540f6e142d59 | 216 | return dev; |
daniele | 2:540f6e142d59 | 217 | } |
daniele | 2:540f6e142d59 | 218 | return NULL; |
daniele | 2:540f6e142d59 | 219 | } |
daniele | 2:540f6e142d59 | 220 | |
daniele | 2:540f6e142d59 | 221 | int pico_device_broadcast(struct pico_frame * f) |
daniele | 2:540f6e142d59 | 222 | { |
daniele | 2:540f6e142d59 | 223 | struct pico_tree_node * index; |
daniele | 2:540f6e142d59 | 224 | int ret = -1; |
daniele | 2:540f6e142d59 | 225 | |
daniele | 2:540f6e142d59 | 226 | pico_tree_foreach(index,&Device_tree) |
daniele | 2:540f6e142d59 | 227 | { |
daniele | 2:540f6e142d59 | 228 | struct pico_device * dev = index->keyValue; |
daniele | 2:540f6e142d59 | 229 | if(dev != f->dev) |
daniele | 2:540f6e142d59 | 230 | { |
daniele | 2:540f6e142d59 | 231 | struct pico_frame * copy = pico_frame_copy(f); |
daniele | 2:540f6e142d59 | 232 | |
daniele | 2:540f6e142d59 | 233 | if(!copy) |
daniele | 2:540f6e142d59 | 234 | return -1; |
daniele | 2:540f6e142d59 | 235 | copy->dev = dev; |
daniele | 2:540f6e142d59 | 236 | copy->dev->send(copy->dev, copy->start, copy->len); |
daniele | 2:540f6e142d59 | 237 | pico_frame_discard(copy); |
daniele | 2:540f6e142d59 | 238 | } |
daniele | 2:540f6e142d59 | 239 | else |
daniele | 2:540f6e142d59 | 240 | { |
daniele | 2:540f6e142d59 | 241 | ret = f->dev->send(f->dev, f->start, f->len); |
daniele | 2:540f6e142d59 | 242 | } |
daniele | 2:540f6e142d59 | 243 | } |
daniele | 2:540f6e142d59 | 244 | |
daniele | 2:540f6e142d59 | 245 | return ret; |
daniele | 2:540f6e142d59 | 246 | } |