fp@39: /****************************************************************************** fp@0: * fp@54: * d e v i c e . c fp@0: * fp@0: * Methoden für ein EtherCAT-Gerät. fp@0: * fp@39: * $Id$ fp@0: * fp@39: *****************************************************************************/ fp@0: fp@24: #include fp@0: #include fp@0: #include fp@0: #include fp@2: #include fp@0: fp@54: #include "device.h" fp@78: #include "master.h" fp@0: fp@39: /*****************************************************************************/ fp@0: fp@0: /** fp@0: EtherCAT-Geräte-Konstuktor. fp@78: */ fp@78: fp@78: int ec_device_init(ec_device_t *device, /**< EtherCAT-Gerät */ fp@78: ec_master_t *master /**< Zugehöriger Master */ fp@78: ) fp@78: { fp@78: device->master = master; fp@78: device->dev = NULL; fp@78: device->open = 0; fp@78: device->tx_time = 0; fp@78: device->rx_time = 0; fp@78: device->state = EC_DEVICE_STATE_READY; fp@78: device->rx_data_size = 0; fp@78: device->isr = NULL; fp@78: device->module = NULL; fp@78: device->error_reported = 0; fp@78: fp@78: if ((device->tx_skb = dev_alloc_skb(ETH_HLEN + EC_MAX_FRAME_SIZE)) == NULL) { fp@84: EC_ERR("Error allocating device socket buffer!\n"); fp@73: return -1; fp@73: } fp@73: fp@73: return 0; fp@39: } fp@39: fp@39: /*****************************************************************************/ fp@0: fp@0: /** fp@0: EtherCAT-Geräte-Destuktor. fp@5: fp@0: Gibt den dynamisch allozierten Speicher des fp@0: EtherCAT-Gerätes (die beiden Socket-Buffer) wieder frei. fp@78: */ fp@78: fp@78: void ec_device_clear(ec_device_t *device /**< EtherCAT-Gerät */) fp@78: { fp@78: if (device->open) ec_device_close(device); fp@78: fp@78: device->dev = NULL; fp@78: fp@78: if (device->tx_skb) { fp@78: dev_kfree_skb(device->tx_skb); fp@78: device->tx_skb = NULL; fp@73: } fp@0: } fp@0: fp@39: /*****************************************************************************/ fp@0: fp@0: /** fp@0: Führt die open()-Funktion des Netzwerktreibers aus. fp@0: fp@0: Dies entspricht einem "ifconfig up". Vorher wird der Zeiger fp@0: auf das EtherCAT-Gerät auf Gültigkeit geprüft und der fp@0: Gerätezustand zurückgesetzt. fp@0: fp@78: \return 0 bei Erfolg, < 0: Ungültiger Zeiger, oder open() fp@78: fehlgeschlagen fp@78: */ fp@78: fp@78: int ec_device_open(ec_device_t *device /**< EtherCAT-Gerät */) fp@0: { fp@73: unsigned int i; fp@73: fp@78: if (!device) { fp@84: EC_ERR("Trying to open a NULL device!\n"); fp@73: return -1; fp@73: } fp@73: fp@78: if (!device->dev) { fp@84: EC_ERR("No net_device to open!\n"); fp@73: return -1; fp@73: } fp@73: fp@78: if (device->open) { fp@84: EC_WARN("Device already opened!\n"); fp@73: } fp@73: else { fp@73: // Device could have received frames before fp@78: for (i = 0; i < 4; i++) ec_device_call_isr(device); fp@73: fp@73: // Reset old device state fp@78: device->state = EC_DEVICE_STATE_READY; fp@78: fp@78: if (device->dev->open(device->dev) == 0) device->open = 1; fp@78: } fp@78: fp@78: return device->open ? 0 : -1; fp@0: } fp@0: fp@39: /*****************************************************************************/ fp@0: fp@0: /** fp@0: Führt die stop()-Funktion des net_devices aus. fp@0: fp@78: \return 0 bei Erfolg, < 0: Kein Gerät zum Schliessen oder fp@73: Schliessen fehlgeschlagen. fp@54: */ fp@54: fp@78: int ec_device_close(ec_device_t *device /**< EtherCAT-Gerät */) fp@78: { fp@78: if (!device->dev) { fp@84: EC_ERR("No device to close!\n"); fp@73: return -1; fp@73: } fp@73: fp@78: if (!device->open) { fp@84: EC_WARN("Device already closed!\n"); fp@73: } fp@73: else { fp@78: if (device->dev->stop(device->dev) == 0) device->open = 0; fp@78: } fp@78: fp@78: return !device->open ? 0 : -1; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Bereitet den geräteinternen Socket-Buffer auf den Versand vor. fp@73: fp@73: \return Zeiger auf den Speicher, in den die Frame-Daten sollen. fp@73: */ fp@73: fp@78: uint8_t *ec_device_prepare(ec_device_t *device /**< EtherCAT-Gerät */) fp@73: { fp@73: // Clear transmit socket buffer and reserve space for Ethernet-II header fp@78: skb_trim(device->tx_skb, 0); fp@78: skb_reserve(device->tx_skb, ETH_HLEN); fp@73: fp@73: // Erstmal Speicher für maximal langen Frame reservieren fp@78: return skb_put(device->tx_skb, EC_MAX_FRAME_SIZE); fp@0: } fp@0: fp@39: /*****************************************************************************/ fp@0: fp@0: /** fp@0: Sendet einen Rahmen über das EtherCAT-Gerät. fp@0: fp@0: Kopiert die zu sendenden Daten in den statischen Socket- fp@0: Buffer, fügt den Ethernat-II-Header hinzu und ruft die fp@0: start_xmit()-Funktion der Netzwerkkarte auf. fp@0: fp@73: \return 0 bei Erfolg, < 0: Vorheriger Rahmen noch fp@0: nicht empfangen, oder kein Speicher mehr vorhanden fp@0: */ fp@0: fp@78: void ec_device_send(ec_device_t *device, /**< EtherCAT-Gerät */ fp@73: unsigned int length /**< Länge der zu sendenden Daten */ fp@73: ) fp@73: { fp@73: struct ethhdr *eth; fp@73: fp@73: // Framegroesse auf (jetzt bekannte) Laenge abschneiden fp@78: skb_trim(device->tx_skb, length); fp@73: fp@73: // Ethernet-II-Header hinzufuegen fp@78: eth = (struct ethhdr *) skb_push(device->tx_skb, ETH_HLEN); fp@73: eth->h_proto = htons(0x88A4); fp@78: memcpy(eth->h_source, device->dev->dev_addr, device->dev->addr_len); fp@78: memset(eth->h_dest, 0xFF, device->dev->addr_len); fp@78: fp@78: device->state = EC_DEVICE_STATE_SENT; fp@78: device->rx_data_size = 0; fp@78: fp@78: if (unlikely(device->master->debug_level > 1)) { fp@84: EC_DBG("Sending frame:\n"); fp@78: ec_data_print(device->tx_skb->data + ETH_HLEN, device->tx_skb->len); fp@78: } fp@73: fp@73: // Senden einleiten fp@78: rdtscl(device->tx_time); // Get CPU cycles fp@78: device->dev->hard_start_xmit(device->tx_skb, device->dev); fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Gibt die Anzahl der empfangenen Bytes zurück. fp@73: fp@73: \return Empfangene Bytes, oder 0, wenn kein Frame empfangen wurde. fp@73: */ fp@73: fp@78: unsigned int ec_device_received(const ec_device_t *device) fp@78: { fp@78: return device->rx_data_size; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Gibt die empfangenen Daten zurück. fp@73: fp@73: \return Adresse auf empfangene Daten. fp@73: */ fp@73: fp@78: uint8_t *ec_device_data(ec_device_t *device) fp@78: { fp@78: return device->rx_data; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@73: Ruft die Interrupt-Routine der Netzwerkkarte auf. fp@78: */ fp@78: fp@78: void ec_device_call_isr(ec_device_t *device /**< EtherCAT-Gerät */) fp@78: { fp@78: if (likely(device->isr)) device->isr(0, device->dev, NULL); fp@39: } fp@39: fp@39: /*****************************************************************************/ fp@5: fp@5: /** fp@0: Gibt alle Informationen über das Device-Objekt aus. fp@78: */ fp@78: fp@78: void ec_device_print(ec_device_t *device /**< EtherCAT-Gerät */) fp@73: { fp@84: EC_DBG("---EtherCAT device information begin---\n"); fp@84: fp@84: if (device) { fp@84: EC_DBG("Assigned net_device: %X\n", (u32) device->dev); fp@84: EC_DBG("Transmit socket buffer: %X\n", (u32) device->tx_skb); fp@84: EC_DBG("Time of last transmission: %u\n", (u32) device->tx_time); fp@84: EC_DBG("Time of last receive: %u\n", (u32) device->rx_time); fp@84: EC_DBG("Actual device state: %i\n", (u8) device->state); fp@84: EC_DBG("Receive buffer: %X\n", (u32) device->rx_data); fp@84: EC_DBG("Receive buffer fill state: %u/%u\n", fp@84: (u32) device->rx_data_size, EC_MAX_FRAME_SIZE); fp@84: } fp@84: else { fp@84: EC_DBG("Device is NULL!\n"); fp@84: } fp@84: fp@84: EC_DBG("---EtherCAT device information end---\n"); fp@0: } fp@0: fp@78: /*****************************************************************************/ fp@78: fp@78: /** fp@78: Gibt das letzte Rahmenpaar aus. fp@78: */ fp@78: fp@78: void ec_device_debug(const ec_device_t *device /**< EtherCAT-Gerät */) fp@78: { fp@84: EC_DBG(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); fp@78: ec_data_print(device->tx_skb->data + ETH_HLEN, device->tx_skb->len); fp@84: EC_DBG("------------------------------------------------\n"); fp@78: ec_data_print_diff(device->tx_skb->data + ETH_HLEN, device->rx_data, fp@78: device->rx_data_size); fp@84: EC_DBG("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n"); fp@78: } fp@78: fp@78: /*****************************************************************************/ fp@78: fp@78: /** fp@78: Gibt Frame-Inhalte zwecks Debugging aus. fp@78: */ fp@78: fp@78: void ec_data_print(const uint8_t *data /**< Daten */, fp@78: size_t size /**< Anzahl Bytes */ fp@78: ) fp@78: { fp@78: size_t i; fp@78: fp@84: EC_DBG(""); fp@78: for (i = 0; i < size; i++) { fp@78: printk("%02X ", data[i]); fp@84: if ((i + 1) % 16 == 0) { fp@84: printk("\n"); fp@84: EC_DBG(""); fp@84: } fp@78: } fp@78: printk("\n"); fp@78: } fp@78: fp@78: /*****************************************************************************/ fp@78: fp@78: /** fp@78: Gibt Frame-Inhalte zwecks Debugging aus, differentiell. fp@78: */ fp@78: fp@78: void ec_data_print_diff(const uint8_t *d1, /**< Daten 1 */ fp@78: const uint8_t *d2, /**< Daten 2 */ fp@78: size_t size /** Anzahl Bytes */ fp@78: ) fp@78: { fp@78: size_t i; fp@78: fp@84: EC_DBG(""); fp@78: for (i = 0; i < size; i++) { fp@78: if (d1[i] == d2[i]) printk(".. "); fp@78: else printk("%02X ", d2[i]); fp@84: if ((i + 1) % 16 == 0) { fp@84: printk("\n"); fp@84: EC_DBG(""); fp@84: } fp@78: } fp@78: printk("\n"); fp@78: } fp@78: fp@54: /****************************************************************************** fp@54: * fp@54: * Treiberschnittstelle fp@54: * fp@54: *****************************************************************************/ fp@54: fp@78: /** fp@78: Setzt den Zustand des EtherCAT-Gerätes. fp@78: */ fp@78: fp@78: void EtherCAT_dev_state(ec_device_t *device, /**< EtherCAT-Gerät */ fp@78: ec_device_state_t state /**< Neuer Zustand */ fp@78: ) fp@78: { fp@78: device->state = state; fp@78: } fp@78: fp@78: /*****************************************************************************/ fp@78: fp@78: /** fp@78: Prüft, ob das Net-Device \a dev zum registrierten EtherCAT-Gerät gehört. fp@78: */ fp@78: fp@78: int EtherCAT_dev_is_ec(const ec_device_t *device, /**< EtherCAT-Gerät */ fp@78: const struct net_device *dev /**< Net-Device */ fp@78: ) fp@78: { fp@78: return device && device->dev == dev; fp@78: } fp@78: fp@78: /*****************************************************************************/ fp@78: fp@78: void EtherCAT_dev_receive(ec_device_t *device, const void *data, size_t size) fp@73: { fp@73: // Copy received data to ethercat-device buffer fp@78: memcpy(device->rx_data, data, size); fp@78: device->rx_data_size = size; fp@78: device->state = EC_DEVICE_STATE_RECEIVED; fp@78: fp@78: if (unlikely(device->master->debug_level > 1)) { fp@84: EC_DBG("Received frame:\n"); fp@78: ec_data_print_diff(device->tx_skb->data + ETH_HLEN, device->rx_data, fp@78: device->rx_data_size); fp@78: } fp@54: } fp@54: fp@54: /*****************************************************************************/ fp@54: fp@54: EXPORT_SYMBOL(EtherCAT_dev_is_ec); fp@54: EXPORT_SYMBOL(EtherCAT_dev_state); fp@54: EXPORT_SYMBOL(EtherCAT_dev_receive); fp@27: fp@39: /*****************************************************************************/ fp@42: fp@42: /* Emacs-Konfiguration fp@42: ;;; Local Variables: *** fp@73: ;;; c-basic-offset:4 *** fp@42: ;;; End: *** fp@42: */