fp@1613: /****************************************************************************** fp@1613: * fp@1613: * $Id$ fp@1613: * fp@1613: * Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH fp@1613: * fp@1613: * This file is part of the IgH EtherCAT Master. fp@1613: * fp@1613: * The IgH EtherCAT Master is free software; you can redistribute it and/or fp@1613: * modify it under the terms of the GNU General Public License version 2, as fp@1613: * published by the Free Software Foundation. fp@1613: * fp@1613: * The IgH EtherCAT Master is distributed in the hope that it will be useful, fp@1613: * but WITHOUT ANY WARRANTY; without even the implied warranty of fp@1613: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General fp@1613: * Public License for more details. fp@1613: * fp@1613: * You should have received a copy of the GNU General Public License along fp@1613: * with the IgH EtherCAT Master; if not, write to the Free Software fp@1613: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA fp@1613: * fp@1613: * --- fp@1613: * fp@1613: * The license mentioned above concerns the source code only. Using the fp@1613: * EtherCAT technology and brand is only permitted in compliance with the fp@1613: * industrial property and similar rights of Beckhoff Automation GmbH. fp@1613: * fp@1613: *****************************************************************************/ fp@1613: fp@1613: #include fp@1613: #include fp@1779: #include fp@1975: #include fp@1613: fp@1613: #include "../../include/ecrt.h" // EtherCAT realtime interface fp@1613: #include "../../include/ectty.h" // EtherCAT TTY interface fp@1613: fp@1613: /*****************************************************************************/ fp@1613: fp@1613: // Optional features fp@1613: #define PFX "ec_tty_example: " fp@1613: fp@1782: #define DEBUG 0 fp@1782: fp@1613: /*****************************************************************************/ fp@1613: fp@1613: #define VendorIdBeckhoff 0x00000002 fp@1613: #define ProductCodeBeckhoffEL6002 0x17723052 fp@1783: fp@1783: #define VendorIdIds 0x000012ad fp@1783: #define ProductCodeIdsCSI71A 0x17723052 fp@1783: fp@1783: /*****************************************************************************/ fp@1613: fp@1613: typedef enum { fp@1613: SER_REQUEST_INIT, fp@1613: SER_WAIT_FOR_INIT_RESPONSE, fp@1782: SER_READY, fp@1782: SER_SET_RTSCTS, fp@1782: SER_SET_BAUD_RATE, fp@1782: SER_SET_DATA_FRAME, fp@1784: } el60xx_port_state; fp@1613: fp@1785: #define EL6002_PORT_NAME_SIZE 16 fp@1785: fp@1613: typedef struct { fp@1613: ec_tty_t *tty; fp@1785: char name[EL6002_PORT_NAME_SIZE]; fp@1613: fp@1613: size_t max_tx_data_size; fp@1613: size_t max_rx_data_size; fp@1613: fp@1613: u8 *tx_data; fp@1613: u8 tx_data_size; fp@1613: fp@1784: el60xx_port_state state; fp@1613: fp@1613: u8 tx_request_toggle; fp@1613: u8 tx_accepted_toggle; fp@1613: fp@1613: u8 rx_request_toggle; fp@1613: u8 rx_accepted_toggle; fp@1613: fp@1613: u16 control; fp@1613: fp@1613: u32 off_ctrl; fp@1613: u32 off_tx; fp@1613: u32 off_status; fp@1613: u32 off_rx; fp@1780: fp@1782: ec_sdo_request_t *rtscts_sdo; fp@1782: u8 requested_rtscts; fp@1782: u8 current_rtscts; fp@1782: fp@1782: ec_sdo_request_t *baud_sdo; fp@1782: u8 requested_baud_rate; fp@1782: u8 current_baud_rate; fp@1782: fp@1782: ec_sdo_request_t *frame_sdo; fp@1782: u8 requested_data_frame; fp@1782: u8 current_data_frame; fp@1782: fp@1782: unsigned int config_error; fp@1780: fp@1784: } el60xx_port_t; fp@1784: fp@1784: #define EL6002_PORTS 2 fp@1784: fp@1784: typedef struct { fp@1784: struct list_head list; fp@1784: ec_slave_config_t *sc; fp@1784: el60xx_port_t port[EL6002_PORTS]; fp@1613: } el6002_t; fp@1613: fp@1615: LIST_HEAD(handlers); fp@2421: fp@1613: /*****************************************************************************/ fp@1613: fp@1613: /* Beckhoff EL6002 fp@1613: * Vendor ID: 0x00000002 fp@1613: * Product code: 0x17723052 fp@1613: * Revision number: 0x00100000 fp@1613: */ fp@1613: fp@1613: ec_pdo_entry_info_t el6002_pdo_entries[] = { fp@1613: {0x7001, 0x01, 16}, /* Ctrl */ fp@1613: {0x7000, 0x11, 8}, /* Data Out 0 */ fp@1613: {0x7000, 0x12, 8}, /* Data Out 1 */ fp@1613: {0x7000, 0x13, 8}, /* Data Out 2 */ fp@1613: {0x7000, 0x14, 8}, /* Data Out 3 */ fp@1613: {0x7000, 0x15, 8}, /* Data Out 4 */ fp@1613: {0x7000, 0x16, 8}, /* Data Out 5 */ fp@1613: {0x7000, 0x17, 8}, /* Data Out 6 */ fp@1613: {0x7000, 0x18, 8}, /* Data Out 7 */ fp@1613: {0x7000, 0x19, 8}, /* Data Out 8 */ fp@1613: {0x7000, 0x1a, 8}, /* Data Out 9 */ fp@1613: {0x7000, 0x1b, 8}, /* Data Out 10 */ fp@1613: {0x7000, 0x1c, 8}, /* Data Out 11 */ fp@1613: {0x7000, 0x1d, 8}, /* Data Out 12 */ fp@1613: {0x7000, 0x1e, 8}, /* Data Out 13 */ fp@1613: {0x7000, 0x1f, 8}, /* Data Out 14 */ fp@1613: {0x7000, 0x20, 8}, /* Data Out 15 */ fp@1613: {0x7000, 0x21, 8}, /* Data Out 16 */ fp@1613: {0x7000, 0x22, 8}, /* Data Out 17 */ fp@1613: {0x7000, 0x23, 8}, /* Data Out 18 */ fp@1613: {0x7000, 0x24, 8}, /* Data Out 19 */ fp@1613: {0x7000, 0x25, 8}, /* Data Out 20 */ fp@1613: {0x7000, 0x26, 8}, /* Data Out 21 */ fp@1613: {0x7011, 0x01, 16}, /* Ctrl */ fp@1613: {0x7010, 0x11, 8}, /* Data Out 0 */ fp@1613: {0x7010, 0x12, 8}, /* Data Out 1 */ fp@1613: {0x7010, 0x13, 8}, /* Data Out 2 */ fp@1613: {0x7010, 0x14, 8}, /* Data Out 3 */ fp@1613: {0x7010, 0x15, 8}, /* Data Out 4 */ fp@1613: {0x7010, 0x16, 8}, /* Data Out 5 */ fp@1613: {0x7010, 0x17, 8}, /* Data Out 6 */ fp@1613: {0x7010, 0x18, 8}, /* Data Out 7 */ fp@1613: {0x7010, 0x19, 8}, /* Data Out 8 */ fp@1613: {0x7010, 0x1a, 8}, /* Data Out 9 */ fp@1613: {0x7010, 0x1b, 8}, /* Data Out 10 */ fp@1613: {0x7010, 0x1c, 8}, /* Data Out 11 */ fp@1613: {0x7010, 0x1d, 8}, /* Data Out 12 */ fp@1613: {0x7010, 0x1e, 8}, /* Data Out 13 */ fp@1613: {0x7010, 0x1f, 8}, /* Data Out 14 */ fp@1613: {0x7010, 0x20, 8}, /* Data Out 15 */ fp@1613: {0x7010, 0x21, 8}, /* Data Out 16 */ fp@1613: {0x7010, 0x22, 8}, /* Data Out 17 */ fp@1613: {0x7010, 0x23, 8}, /* Data Out 18 */ fp@1613: {0x7010, 0x24, 8}, /* Data Out 19 */ fp@1613: {0x7010, 0x25, 8}, /* Data Out 20 */ fp@1613: {0x7010, 0x26, 8}, /* Data Out 21 */ fp@1613: {0x6001, 0x01, 16}, /* Status */ fp@1613: {0x6000, 0x11, 8}, /* Data In 0 */ fp@1613: {0x6000, 0x12, 8}, /* Data In 1 */ fp@1613: {0x6000, 0x13, 8}, /* Data In 2 */ fp@1613: {0x6000, 0x14, 8}, /* Data In 3 */ fp@1613: {0x6000, 0x15, 8}, /* Data In 4 */ fp@1613: {0x6000, 0x16, 8}, /* Data In 5 */ fp@1613: {0x6000, 0x17, 8}, /* Data In 6 */ fp@1613: {0x6000, 0x18, 8}, /* Data In 7 */ fp@1613: {0x6000, 0x19, 8}, /* Data In 8 */ fp@1613: {0x6000, 0x1a, 8}, /* Data In 9 */ fp@1613: {0x6000, 0x1b, 8}, /* Data In 10 */ fp@1613: {0x6000, 0x1c, 8}, /* Data In 11 */ fp@1613: {0x6000, 0x1d, 8}, /* Data In 12 */ fp@1613: {0x6000, 0x1e, 8}, /* Data In 13 */ fp@1613: {0x6000, 0x1f, 8}, /* Data In 14 */ fp@1613: {0x6000, 0x20, 8}, /* Data In 15 */ fp@1613: {0x6000, 0x21, 8}, /* Data In 16 */ fp@1613: {0x6000, 0x22, 8}, /* Data In 17 */ fp@1613: {0x6000, 0x23, 8}, /* Data In 18 */ fp@1613: {0x6000, 0x24, 8}, /* Data In 19 */ fp@1613: {0x6000, 0x25, 8}, /* Data In 20 */ fp@1613: {0x6000, 0x26, 8}, /* Data In 21 */ fp@1613: {0x6011, 0x01, 16}, /* Status */ fp@1613: {0x6010, 0x11, 8}, /* Data In 0 */ fp@1613: {0x6010, 0x12, 8}, /* Data In 1 */ fp@1613: {0x6010, 0x13, 8}, /* Data In 2 */ fp@1613: {0x6010, 0x14, 8}, /* Data In 3 */ fp@1613: {0x6010, 0x15, 8}, /* Data In 4 */ fp@1613: {0x6010, 0x16, 8}, /* Data In 5 */ fp@1613: {0x6010, 0x17, 8}, /* Data In 6 */ fp@1613: {0x6010, 0x18, 8}, /* Data In 7 */ fp@1613: {0x6010, 0x19, 8}, /* Data In 8 */ fp@1613: {0x6010, 0x1a, 8}, /* Data In 9 */ fp@1613: {0x6010, 0x1b, 8}, /* Data In 10 */ fp@1613: {0x6010, 0x1c, 8}, /* Data In 11 */ fp@1613: {0x6010, 0x1d, 8}, /* Data In 12 */ fp@1613: {0x6010, 0x1e, 8}, /* Data In 13 */ fp@1613: {0x6010, 0x1f, 8}, /* Data In 14 */ fp@1613: {0x6010, 0x20, 8}, /* Data In 15 */ fp@1613: {0x6010, 0x21, 8}, /* Data In 16 */ fp@1613: {0x6010, 0x22, 8}, /* Data In 17 */ fp@1613: {0x6010, 0x23, 8}, /* Data In 18 */ fp@1613: {0x6010, 0x24, 8}, /* Data In 19 */ fp@1613: {0x6010, 0x25, 8}, /* Data In 20 */ fp@1613: {0x6010, 0x26, 8}, /* Data In 21 */ fp@1613: }; fp@1613: fp@1613: ec_pdo_info_t el6002_pdos[] = { fp@1613: {0x1604, 23, el6002_pdo_entries + 0}, /* COM RxPDO-Map Outputs Ch.1 */ fp@1613: {0x1605, 23, el6002_pdo_entries + 23}, /* COM RxPDO-Map Outputs Ch.2 */ fp@1613: {0x1a04, 23, el6002_pdo_entries + 46}, /* COM TxPDO-Map Inputs Ch.1 */ fp@1613: {0x1a05, 23, el6002_pdo_entries + 69}, /* COM TxPDO-Map Inputs Ch.2 */ fp@1613: }; fp@1613: fp@1613: ec_sync_info_t el6002_syncs[] = { fp@1613: {0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE}, fp@1613: {1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE}, fp@1613: {2, EC_DIR_OUTPUT, 2, el6002_pdos + 0, EC_WD_DISABLE}, fp@1613: {3, EC_DIR_INPUT, 2, el6002_pdos + 2, EC_WD_DISABLE}, fp@1613: {0xff} fp@1613: }; fp@1613: fp@1780: typedef enum { fp@1780: PAR_NONE, fp@1780: PAR_ODD, fp@1780: PAR_EVEN fp@1780: } parity_t; fp@1780: fp@1780: typedef struct { fp@1780: u8 value; fp@1782: unsigned int data_bits; fp@1780: parity_t parity; fp@1782: unsigned int stop_bits; fp@1780: } el600x_data_frame_t; fp@1780: fp@1782: /** EL600x supported values for data frame SDO. fp@1780: */ fp@1780: el600x_data_frame_t el600x_data_frame[] = { fp@1780: {0x01, 7, PAR_EVEN, 1}, fp@1780: {0x09, 7, PAR_EVEN, 2}, fp@1780: {0x02, 7, PAR_ODD, 1}, fp@1780: {0x0a, 7, PAR_ODD, 2}, fp@1780: {0x03, 8, PAR_NONE, 1}, fp@1780: {0x0b, 8, PAR_NONE, 2}, fp@1780: {0x04, 8, PAR_EVEN, 1}, fp@1780: {0x0c, 8, PAR_EVEN, 2}, fp@1780: {0x05, 8, PAR_ODD, 1}, fp@1780: {0x0d, 8, PAR_ODD, 2}, fp@1780: }; fp@1780: fp@1782: typedef struct { fp@1782: u8 value; fp@1782: unsigned int baud; fp@1782: tcflag_t cbaud; fp@1782: } el600x_baud_rate_t; fp@1782: fp@1782: /** EL600x supported values for baud rate SDO. fp@1782: */ fp@1782: el600x_baud_rate_t el600x_baud_rate[] = { fp@1782: {1, 300, B300}, fp@1782: {2, 600, B600}, fp@1782: {3, 1200, B1200}, fp@1782: {4, 2400, B2400}, fp@1782: {5, 4800, B4800}, fp@1782: {6, 9600, B9600}, fp@1782: {7, 19200, B19200}, fp@1782: {8, 38400, B38400}, fp@1782: {9, 57600, B57600}, fp@1782: {10, 115200, B115200} fp@1782: }; fp@1782: fp@1613: /****************************************************************************/ fp@1613: fp@1784: int el60xx_cflag_changed(void *data, tcflag_t cflag) fp@1784: { fp@1784: el60xx_port_t *port = (el60xx_port_t *) data; fp@1782: unsigned int data_bits, stop_bits; fp@1782: tcflag_t cbaud, rtscts; fp@1780: parity_t par; fp@1780: unsigned int i; fp@1782: el600x_baud_rate_t *b_to_use = NULL; fp@1780: el600x_data_frame_t *df_to_use = NULL; fp@1779: fp@1782: #if DEBUG fp@1785: printk(KERN_INFO PFX "%s(%s, cflag=%x).\n", __func__, port->name, cflag); fp@1782: #endif fp@1782: fp@1782: rtscts = cflag & CRTSCTS; fp@1785: printk(KERN_INFO PFX "%s: Requested RTS/CTS: %s.\n", fp@1785: port->name, rtscts ? "yes" : "no"); fp@2421: fp@1782: cbaud = cflag & CBAUD; fp@1782: fp@1782: for (i = 0; i < sizeof(el600x_baud_rate) / sizeof(el600x_baud_rate_t); fp@1782: i++) { fp@1782: el600x_baud_rate_t *b = el600x_baud_rate + i; fp@1782: if (b->cbaud == cbaud) { fp@1782: b_to_use = b; fp@1782: break; fp@1782: } fp@1782: } fp@1782: fp@1782: if (b_to_use) { fp@1785: printk(KERN_INFO PFX "%s: Requested baud rate: %u.\n", fp@1785: port->name, b_to_use->baud); fp@1782: } else { fp@1785: printk(KERN_ERR PFX "Error: %s does not support" fp@1785: " baud rate index %x.\n", port->name, cbaud); fp@1782: return -EINVAL; fp@1782: } fp@1779: fp@1779: switch (cflag & CSIZE) { fp@1780: case CS5: fp@1780: data_bits = 5; fp@1780: break; fp@1780: case CS6: fp@1780: data_bits = 6; fp@1780: break; fp@1779: case CS7: fp@1780: data_bits = 7; fp@1779: break; fp@1779: case CS8: fp@1780: data_bits = 8; fp@1779: break; fp@1779: default: /* CS5 or CS6 */ fp@1780: data_bits = 0; fp@1780: } fp@1779: fp@1779: if (cflag & PARENB) { fp@1780: par = (cflag & PARODD) ? PAR_ODD : PAR_EVEN; fp@1779: } else { fp@1780: par = PAR_NONE; fp@1780: } fp@1780: fp@1780: stop_bits = (cflag & CSTOPB) ? 2 : 1; fp@1780: fp@1785: printk(KERN_INFO PFX "%s: Requested Data frame: %u%c%u.\n", fp@1785: port->name, data_bits, fp@1780: (par == PAR_NONE ? 'N' : (par == PAR_ODD ? 'O' : 'E')), fp@1780: stop_bits); fp@1780: fp@1780: for (i = 0; i < sizeof(el600x_data_frame) / sizeof(el600x_data_frame_t); fp@1780: i++) { fp@1780: el600x_data_frame_t *df = el600x_data_frame + i; fp@1780: if (df->data_bits == data_bits && fp@1780: df->parity == par && fp@1780: df->stop_bits == stop_bits) { fp@1780: df_to_use = df; fp@1780: break; fp@1780: } fp@1780: } fp@1780: fp@1780: if (!df_to_use) { fp@1785: printk(KERN_ERR PFX "Error: %s does not support data frame type.\n", fp@1785: port->name); fp@1780: return -EINVAL; fp@1780: } fp@1780: fp@1784: port->requested_rtscts = rtscts != 0; fp@1784: port->requested_baud_rate = b_to_use->value; fp@1784: port->requested_data_frame = df_to_use->value; fp@1784: port->config_error = 0; fp@1779: return 0; fp@1779: } fp@1779: fp@1779: /****************************************************************************/ fp@1779: fp@1787: static ec_tty_operations_t el60xx_tty_ops = { fp@1787: .cflag_changed = el60xx_cflag_changed, fp@1787: }; fp@1787: fp@1787: /****************************************************************************/ fp@1787: fp@1784: int el60xx_port_init(el60xx_port_t *port, ec_slave_config_t *sc, fp@1785: ec_domain_t *domain, unsigned int slot_offset, const char *name) fp@1784: { fp@1784: int ret = 0; fp@1784: fp@1785: strncpy(port->name, name, EL6002_PORT_NAME_SIZE); fp@1785: fp@1787: port->tty = ectty_create(&el60xx_tty_ops, port); fp@1784: if (IS_ERR(port->tty)) { fp@1785: printk(KERN_ERR PFX "Failed to create tty for %s.\n", fp@1785: port->name); fp@1784: ret = PTR_ERR(port->tty); fp@1784: goto out_return; fp@1784: } fp@1784: fp@1784: port->max_tx_data_size = 22; fp@1784: port->max_rx_data_size = 22; fp@1784: port->tx_data = NULL; fp@1784: port->tx_data_size = 0; fp@1784: port->state = SER_REQUEST_INIT; fp@1784: port->tx_request_toggle = 0; fp@1784: port->rx_accepted_toggle = 0; fp@1784: port->control = 0x0000; fp@1784: port->off_ctrl = 0; fp@1784: port->off_tx = 0; fp@1784: port->off_status = 0; fp@1784: port->off_rx = 0; fp@1784: port->requested_rtscts = 0x00; // no hardware handshake fp@1784: port->current_rtscts = 0xff; fp@1784: port->requested_baud_rate = 6; // 9600 fp@1784: port->current_baud_rate = 0; fp@1784: port->requested_data_frame = 0x03; // 8N1 fp@1784: port->current_data_frame = 0x00; fp@1784: port->config_error = 0; fp@1784: fp@1784: if (!(port->rtscts_sdo = ecrt_slave_config_create_sdo_request(sc, fp@1784: 0x8000 + slot_offset, 0x01, 1))) { fp@1785: printk(KERN_ERR PFX "Failed to create SDO request for %s.\n", fp@1785: port->name); fp@1784: ret = -ENOMEM; fp@1784: goto out_free_tty; fp@1784: } fp@1784: fp@1784: if (!(port->baud_sdo = ecrt_slave_config_create_sdo_request(sc, fp@1784: 0x8000 + slot_offset, 0x11, 1))) { fp@1785: printk(KERN_ERR PFX "Failed to create SDO request for %s.\n", fp@1785: port->name); fp@1784: ret = -ENOMEM; fp@1784: goto out_free_tty; fp@1784: } fp@1784: fp@1784: if (!(port->frame_sdo = ecrt_slave_config_create_sdo_request(sc, fp@1784: 0x8000 + slot_offset, 0x15, 1))) { fp@1785: printk(KERN_ERR PFX "Failed to create SDO request for %s\n", fp@1785: port->name); fp@1784: ret = -ENOMEM; fp@1784: goto out_free_tty; fp@1784: } fp@1784: fp@1784: ret = ecrt_slave_config_reg_pdo_entry( fp@1784: sc, 0x7001 + slot_offset, 0x01, domain, NULL); fp@1784: if (ret < 0) { fp@1785: printk(KERN_ERR PFX "Failed to register PDO entry of %s\n", fp@1785: port->name); fp@1784: goto out_free_tty; fp@1784: } fp@1784: port->off_ctrl = ret; fp@1784: fp@1784: ret = ecrt_slave_config_reg_pdo_entry( fp@1784: sc, 0x7000 + slot_offset, 0x11, domain, NULL); fp@1784: if (ret < 0) { fp@1785: printk(KERN_ERR PFX "Failed to register PDO entry of %s.\n", fp@1785: port->name); fp@1784: goto out_free_tty; fp@1784: } fp@1784: port->off_tx = ret; fp@1784: fp@1784: ret = ecrt_slave_config_reg_pdo_entry( fp@1784: sc, 0x6001 + slot_offset, 0x01, domain, NULL); fp@1784: if (ret < 0) { fp@1785: printk(KERN_ERR PFX "Failed to register PDO entry of %s.\n", fp@1785: port->name); fp@1784: goto out_free_tty; fp@1784: } fp@1784: port->off_status = ret; fp@1784: fp@1784: ret = ecrt_slave_config_reg_pdo_entry( fp@1784: sc, 0x6000 + slot_offset, 0x11, domain, NULL); fp@1784: if (ret < 0) { fp@1785: printk(KERN_ERR PFX "Failed to register PDO entry of %s.\n", fp@1785: port->name); fp@1784: goto out_free_tty; fp@1784: } fp@1784: port->off_rx = ret; fp@1784: fp@1784: if (port->max_tx_data_size > 0) { fp@1784: port->tx_data = kmalloc(port->max_tx_data_size, GFP_KERNEL); fp@1784: if (port->tx_data == NULL) { fp@1785: printk(KERN_ERR PFX "Failed to allocate %u bytes of TX" fp@1785: " memory for %s.\n", port->max_tx_data_size, port->name); fp@1784: ret = -ENOMEM; fp@1784: goto out_free_tty; fp@1784: } fp@1784: } fp@1784: fp@1784: return 0; fp@1784: fp@1784: out_free_tty: fp@1784: ectty_free(port->tty); fp@1784: out_return: fp@1784: return ret; fp@1784: } fp@1784: fp@1784: /****************************************************************************/ fp@1784: fp@1784: void el60xx_port_clear(el60xx_port_t *port) fp@1784: { fp@1784: ectty_free(port->tty); fp@1784: if (port->tx_data) { fp@1784: kfree(port->tx_data); fp@1784: } fp@1784: } fp@1784: fp@1784: /****************************************************************************/ fp@1784: fp@1784: void el60xx_port_run(el60xx_port_t *port, u8 *pd) fp@1784: { fp@1784: u16 status = EC_READ_U16(pd + port->off_status); fp@1784: u8 *rx_data = pd + port->off_rx; fp@1784: uint8_t tx_accepted_toggle, rx_request_toggle; fp@1784: fp@1784: switch (port->state) { fp@1784: case SER_READY: fp@1784: fp@1784: /* Check, if hardware handshaking has to be configured. */ fp@1784: if (!port->config_error && fp@1784: port->requested_rtscts != port->current_rtscts) { fp@1784: EC_WRITE_U8(ecrt_sdo_request_data(port->rtscts_sdo), fp@1784: port->requested_rtscts); fp@1784: ecrt_sdo_request_write(port->rtscts_sdo); fp@1784: port->state = SER_SET_RTSCTS; fp@1784: break; fp@1784: } fp@1784: fp@1784: /* Check, if the baud rate has to be configured. */ fp@1784: if (!port->config_error && fp@1784: port->requested_baud_rate != port->current_baud_rate) { fp@1784: EC_WRITE_U8(ecrt_sdo_request_data(port->baud_sdo), fp@1784: port->requested_baud_rate); fp@1784: ecrt_sdo_request_write(port->baud_sdo); fp@1784: port->state = SER_SET_BAUD_RATE; fp@1784: break; fp@1784: } fp@1784: fp@1784: /* Check, if the data frame has to be configured. */ fp@1784: if (!port->config_error && fp@1784: port->requested_data_frame != port->current_data_frame) { fp@1784: EC_WRITE_U8(ecrt_sdo_request_data(port->frame_sdo), fp@1784: port->requested_data_frame); fp@1784: ecrt_sdo_request_write(port->frame_sdo); fp@1784: port->state = SER_SET_DATA_FRAME; fp@1784: break; fp@1784: } fp@1784: fp@1784: /* Send data */ fp@2384: fp@1784: tx_accepted_toggle = status & 0x0001; fp@1784: if (tx_accepted_toggle != port->tx_accepted_toggle) { // ready fp@1784: port->tx_data_size = fp@1784: ectty_tx_data(port->tty, port->tx_data, port->max_tx_data_size); fp@1784: if (port->tx_data_size) { fp@1784: #if DEBUG fp@1785: printk(KERN_INFO PFX "%s: Sending %u bytes.\n", fp@1785: port->name, port->tx_data_size); fp@1784: #endif fp@1784: port->tx_request_toggle = !port->tx_request_toggle; fp@1784: port->tx_accepted_toggle = tx_accepted_toggle; fp@1784: } fp@1784: } fp@1784: fp@1784: /* Receive data */ fp@1784: fp@1784: rx_request_toggle = status & 0x0002; fp@1784: if (rx_request_toggle != port->rx_request_toggle) { fp@1784: uint8_t rx_data_size = status >> 8; fp@1784: port->rx_request_toggle = rx_request_toggle; fp@1784: #if DEBUG fp@1785: printk(KERN_INFO PFX "%s: Received %u bytes.\n", fp@1785: port->name, rx_data_size); fp@1784: #endif fp@1784: ectty_rx_data(port->tty, rx_data, rx_data_size); fp@1784: port->rx_accepted_toggle = !port->rx_accepted_toggle; fp@1784: } fp@1784: fp@1784: port->control = fp@1784: port->tx_request_toggle | fp@1784: port->rx_accepted_toggle << 1 | fp@1784: port->tx_data_size << 8; fp@1784: break; fp@1784: fp@1784: case SER_REQUEST_INIT: fp@1784: if (status & (1 << 2)) { fp@1784: port->control = 0x0000; fp@1784: port->state = SER_WAIT_FOR_INIT_RESPONSE; fp@1784: } else { fp@1784: port->control = 1 << 2; // CW.2, request initialization fp@1784: } fp@1784: break; fp@1784: fp@1784: case SER_WAIT_FOR_INIT_RESPONSE: fp@1784: if (!(status & (1 << 2))) { fp@1785: printk(KERN_INFO PFX "%s: Init successful.\n", port->name); fp@1784: port->tx_accepted_toggle = 1; fp@1784: port->control = 0x0000; fp@1784: port->state = SER_READY; fp@1784: } fp@1784: break; fp@1784: fp@1784: case SER_SET_RTSCTS: fp@1784: switch (ecrt_sdo_request_state(port->rtscts_sdo)) { fp@1784: case EC_REQUEST_SUCCESS: fp@1785: printk(KERN_INFO PFX "%s: Accepted RTS/CTS.\n", fp@1785: port->name); fp@1784: port->current_rtscts = port->requested_rtscts; fp@1784: port->state = SER_REQUEST_INIT; fp@1784: break; fp@1784: case EC_REQUEST_ERROR: fp@1785: printk(KERN_ERR PFX "Failed to set RTS/CTS on %s!\n", fp@1785: port->name); fp@1784: port->state = SER_REQUEST_INIT; fp@1784: port->config_error = 1; fp@1784: break; fp@1784: default: fp@1784: break; fp@1784: } fp@1784: break; fp@1784: fp@1784: case SER_SET_BAUD_RATE: fp@1784: switch (ecrt_sdo_request_state(port->baud_sdo)) { fp@1784: case EC_REQUEST_SUCCESS: fp@1785: printk(KERN_INFO PFX "%s: Accepted baud rate.\n", fp@1785: port->name); fp@1784: port->current_baud_rate = port->requested_baud_rate; fp@1784: port->state = SER_REQUEST_INIT; fp@1784: break; fp@1784: case EC_REQUEST_ERROR: fp@1785: printk(KERN_ERR PFX "Failed to set baud rate on %s!\n", fp@1785: port->name); fp@1784: port->state = SER_REQUEST_INIT; fp@1784: port->config_error = 1; fp@1784: break; fp@1784: default: fp@1784: break; fp@1784: } fp@1784: break; fp@1784: fp@1784: case SER_SET_DATA_FRAME: fp@1784: switch (ecrt_sdo_request_state(port->frame_sdo)) { fp@1784: case EC_REQUEST_SUCCESS: fp@1785: printk(KERN_INFO PFX "%s: Accepted data frame.\n", fp@1785: port->name); fp@1784: port->current_data_frame = port->requested_data_frame; fp@1784: port->state = SER_REQUEST_INIT; fp@1784: break; fp@1784: case EC_REQUEST_ERROR: fp@1785: printk(KERN_ERR PFX "Failed to set data frame on %s!\n", fp@1785: port->name); fp@1784: port->state = SER_REQUEST_INIT; fp@1784: port->config_error = 1; fp@1784: break; fp@1784: default: fp@1784: break; fp@1784: } fp@1784: break; fp@1784: } fp@1784: fp@1784: EC_WRITE_U16(pd + port->off_ctrl, port->control); fp@1784: memcpy(pd + port->off_tx, port->tx_data, port->tx_data_size); fp@1784: } fp@1784: fp@1784: /****************************************************************************/ fp@1784: fp@1784: int el6002_init(el6002_t *el6002, ec_master_t *master, u16 position, fp@1783: ec_domain_t *domain, u32 vendor, u32 product) fp@1613: { fp@1784: int ret = 0, i; fp@1784: fp@1784: if (!(el6002->sc = ecrt_master_slave_config( fp@1783: master, 0, position, vendor, product))) { fp@1785: printk(KERN_ERR PFX "EL6002(%u): Failed to create" fp@1785: " slave configuration.\n", position); fp@1613: ret = -EBUSY; fp@1784: goto out_return; fp@1784: } fp@1784: fp@1784: if (ecrt_slave_config_pdos(el6002->sc, EC_END, el6002_syncs)) { fp@1785: printk(KERN_ERR PFX "EL6002(%u): Failed to configure PDOs.\n", fp@1785: position); fp@1613: ret = -ENOMEM; fp@1784: goto out_return; fp@1784: } fp@1784: fp@1784: for (i = 0; i < EL6002_PORTS; i++) { fp@1785: char name[EL6002_PORT_NAME_SIZE]; fp@1785: snprintf(name, EL6002_PORT_NAME_SIZE, "EL6002(%u) X%u", fp@1785: position, i + 1); fp@1785: if (el60xx_port_init(el6002->port + i, el6002->sc, domain, i * 0x10, fp@1785: name)) { fp@1785: printk(KERN_ERR PFX "EL6002(%u): Failed to init port X%u.\n", fp@1785: position, i); fp@1784: goto out_ports; fp@1613: } fp@1613: } fp@1613: fp@1613: return 0; fp@1613: fp@1784: out_ports: fp@1788: for (i--; i >= 0; i--) { fp@1784: el60xx_port_clear(el6002->port + i); fp@1784: } fp@1613: out_return: fp@1613: return ret; fp@1613: } fp@1613: fp@1613: /****************************************************************************/ fp@1613: fp@1784: void el6002_clear(el6002_t *el6002) fp@1784: { fp@1784: int i; fp@1784: fp@1784: for (i = 0; i < EL6002_PORTS; i++) { fp@1784: el60xx_port_clear(el6002->port + i); fp@1613: } fp@1613: } fp@1613: fp@1613: /****************************************************************************/ fp@1613: fp@1784: void el6002_run(el6002_t *el6002, u8 *pd) fp@1784: { fp@1784: int i; fp@1784: fp@1784: for (i = 0; i < EL6002_PORTS; i++) { fp@1784: el60xx_port_run(el6002->port + i, pd); fp@1784: } fp@1613: } fp@1613: fp@1613: /*****************************************************************************/ fp@1613: fp@1613: void run_serial_devices(u8 *pd) fp@1613: { fp@1784: el6002_t *el6002; fp@1784: fp@1784: list_for_each_entry(el6002, &handlers, list) { fp@1784: el6002_run(el6002, pd); fp@1613: } fp@1613: } fp@1613: fp@1613: /*****************************************************************************/ fp@1613: fp@1783: int create_el6002_handler(ec_master_t *master, ec_domain_t *domain, fp@1783: u16 position, u32 vendor, u32 product) fp@1783: { fp@1784: el6002_t *el6002; fp@1783: int ret; fp@1783: fp@1783: printk(KERN_INFO PFX "Creating handler for EL6002 at position %u\n", fp@1783: position); fp@1783: fp@1784: el6002 = kmalloc(sizeof(*el6002), GFP_KERNEL); fp@1784: if (!el6002) { fp@1783: printk(KERN_ERR PFX "Failed to allocate serial device object.\n"); fp@1783: return -ENOMEM; fp@1783: } fp@1783: fp@1784: ret = el6002_init(el6002, master, position, domain, vendor, product); fp@1783: if (ret) { fp@1784: kfree(el6002); fp@1783: return ret; fp@1783: } fp@1783: fp@1784: list_add_tail(&el6002->list, &handlers); fp@1783: return 0; fp@1783: } fp@1783: fp@1783: /*****************************************************************************/ fp@1783: fp@1613: int create_serial_devices(ec_master_t *master, ec_domain_t *domain) fp@1613: { fp@1613: int i, ret; fp@1613: ec_master_info_t master_info; fp@1613: ec_slave_info_t slave_info; fp@1615: el6002_t *ser, *next; fp@1615: fp@1613: printk(KERN_INFO PFX "Registering serial devices...\n"); fp@1613: fp@1613: ret = ecrt_master(master, &master_info); fp@1613: if (ret) { fp@1613: printk(KERN_ERR PFX "Failed to obtain master information.\n"); fp@1615: goto out_return; fp@1613: } fp@1613: fp@1613: for (i = 0; i < master_info.slave_count; i++) { fp@1613: ret = ecrt_master_get_slave(master, i, &slave_info); fp@1613: if (ret) { fp@1615: printk(KERN_ERR PFX "Failed to obtain slave information.\n"); fp@1615: goto out_free_handlers; fp@1613: } fp@1613: fp@1783: if (slave_info.vendor_id == VendorIdBeckhoff fp@1783: && slave_info.product_code == ProductCodeBeckhoffEL6002) { fp@1783: if (create_el6002_handler(master, domain, i, fp@1783: slave_info.vendor_id, slave_info.product_code)) { fp@1783: goto out_free_handlers; fp@1783: } fp@1613: } fp@1613: fp@1783: if (slave_info.vendor_id == VendorIdIds fp@1783: && slave_info.product_code == ProductCodeIdsCSI71A) { fp@1783: if (create_el6002_handler(master, domain, i, fp@1783: slave_info.vendor_id, slave_info.product_code)) { fp@1783: goto out_free_handlers; fp@1783: } fp@1613: } fp@1783: } fp@1613: fp@1785: printk(KERN_INFO PFX "Finished registering serial devices.\n"); fp@1613: return 0; fp@1615: fp@1615: out_free_handlers: fp@1615: list_for_each_entry_safe(ser, next, &handlers, list) { fp@1615: list_del(&ser->list); fp@1613: el6002_clear(ser); fp@1613: kfree(ser); fp@1613: } fp@1615: out_return: fp@1615: return ret; fp@1615: } fp@1615: fp@1615: /*****************************************************************************/ fp@1615: fp@1615: void free_serial_devices(void) fp@1615: { fp@1615: el6002_t *ser, *next; fp@1615: fp@1615: printk(KERN_INFO PFX "Cleaning up serial devices...\n"); fp@1615: fp@1615: list_for_each_entry_safe(ser, next, &handlers, list) { fp@1615: list_del(&ser->list); fp@1615: el6002_clear(ser); fp@1615: kfree(ser); fp@1615: } fp@1613: fp@1613: printk(KERN_INFO PFX "Finished cleaning up serial devices.\n"); fp@1613: } fp@1613: fp@1613: /*****************************************************************************/