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@91: fp@91: \return 0 wenn alles ok, < 0 bei Fehler (zu wenig Speicher) 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@96: device->link_state = 0; // down 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@91: EtherCAT-Gerätes (den Sende-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->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@91: return 0; fp@91: } fp@91: fp@91: // Device could have received frames before fp@91: for (i = 0; i < 4; i++) ec_device_call_isr(device); fp@91: fp@91: // Reset old device state fp@91: device->state = EC_DEVICE_STATE_READY; fp@96: device->link_state = 0; fp@91: fp@91: if (device->dev->open(device->dev) == 0) device->open = 1; 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@91: \return 0 bei Erfolg, < 0: Kein Gerät zum Schließen oder fp@91: Schließen 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@91: skb_trim(device->tx_skb, 0); // Auf Länge 0 abschneiden fp@91: skb_reserve(device->tx_skb, ETH_HLEN); // Reserve für Ethernet-II-Header fp@91: fp@91: // Vorerst 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@91: Sendet den Inhalt des Socket-Buffers. fp@91: fp@91: Schneidet den Inhalt des Socket-Buffers auf die (nun bekannte) Größe zu, fp@91: fügt den Ethernet-II-Header an und ruft die start_xmit()-Funktion der fp@91: Netzwerkkarte auf. 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@97: if (unlikely(!device->link_state)) // Link down fp@96: return; fp@96: fp@91: // Framegröße auf (jetzt bekannte) Länge 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@91: \return Zeiger 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@91: 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@91: fp@91: \return 0 wenn nein, nicht-null wenn ja. 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@91: /** fp@91: Nimmt einen Empfangenen Rahmen entgegen. fp@91: fp@91: Kopiert die empfangenen Daten in den Receive-Buffer. fp@91: */ fp@91: fp@91: void EtherCAT_dev_receive(ec_device_t *device, /**< EtherCAT-Gerät */ fp@91: const void *data, /**< Zeiger auf empfangene Daten */ fp@91: size_t size /**< Größe der empfangenen Daten */ fp@91: ) 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@96: /** fp@96: Setzt einen neuen Verbindungszustand. fp@96: */ fp@96: fp@96: void EtherCAT_dev_link_state(ec_device_t *device, /**< EtherCAT-Gerät */ fp@96: uint8_t state /**< Verbindungszustand */ fp@96: ) fp@96: { fp@96: if (state != device->link_state) { fp@96: device->link_state = state; fp@96: EC_INFO("Link state changed to %s.\n", (state ? "UP" : "DOWN")); fp@96: } fp@96: } fp@96: fp@96: /*****************************************************************************/ fp@96: fp@54: EXPORT_SYMBOL(EtherCAT_dev_is_ec); fp@54: EXPORT_SYMBOL(EtherCAT_dev_state); fp@54: EXPORT_SYMBOL(EtherCAT_dev_receive); fp@96: EXPORT_SYMBOL(EtherCAT_dev_link_state); 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: */