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@98: void ec_data_print(const uint8_t *, size_t); fp@98: void ec_data_print_diff(const uint8_t *, const uint8_t *, size_t); fp@98: fp@98: /*****************************************************************************/ fp@98: 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@98: ec_master_t *master, /**< Zugehöriger Master */ fp@98: struct net_device *net_dev, /**< Net-Device */ fp@98: ec_isr_t isr, /**< Adresse der ISR */ fp@98: struct module *module /**< Modul-Adresse */ fp@78: ) fp@78: { fp@98: struct ethhdr *eth; fp@98: fp@78: device->master = master; fp@98: device->dev = net_dev; fp@98: device->isr = isr; fp@98: device->module = module; fp@98: fp@78: device->open = 0; fp@96: device->link_state = 0; // down fp@78: fp@98: if (!(device->tx_skb = dev_alloc_skb(ETH_HLEN + EC_MAX_FRAME_SIZE))) { fp@84: EC_ERR("Error allocating device socket buffer!\n"); fp@73: return -1; fp@73: } fp@73: fp@98: device->tx_skb->dev = net_dev; fp@98: fp@98: // Ethernet-II-Header hinzufuegen fp@98: skb_reserve(device->tx_skb, ETH_HLEN); fp@98: eth = (struct ethhdr *) skb_push(device->tx_skb, ETH_HLEN); fp@98: eth->h_proto = htons(0x88A4); fp@98: memcpy(eth->h_source, net_dev->dev_addr, net_dev->addr_len); fp@98: memset(eth->h_dest, 0xFF, net_dev->addr_len); fp@98: 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@98: if (device->tx_skb) dev_kfree_skb(device->tx_skb); 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@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@98: return 0; fp@98: } fp@98: fp@98: if (device->dev->stop(device->dev) == 0) device->open = 0; fp@78: fp@78: return !device->open ? 0 : -1; fp@73: } fp@73: fp@73: /*****************************************************************************/ fp@73: fp@73: /** fp@98: Liefert einen Zeiger auf den Sende-Speicher. fp@73: fp@73: \return Zeiger auf den Speicher, in den die Frame-Daten sollen. fp@73: */ fp@73: fp@98: uint8_t *ec_device_tx_data(ec_device_t *device /**< EtherCAT-Gerät */) fp@98: { fp@98: return device->tx_skb->data + ETH_HLEN; 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@98: size_t size /**< Größe der zu sendenden Daten */ fp@73: ) 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@98: device->tx_skb->len = ETH_HLEN + size; fp@78: fp@78: if (unlikely(device->master->debug_level > 1)) { fp@98: EC_DBG("sending frame:\n"); fp@98: ec_data_print(device->tx_skb->data + ETH_HLEN, size); fp@78: } fp@73: fp@73: // Senden einleiten fp@78: device->dev->hard_start_xmit(device->tx_skb, device->dev); 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@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: 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@78: if (unlikely(device->master->debug_level > 1)) { fp@84: EC_DBG("Received frame:\n"); fp@98: ec_data_print_diff(device->tx_skb->data + ETH_HLEN, data, size); fp@98: } fp@98: fp@98: ec_master_receive(device->master, data, size); 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_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: */