1b482cd20SSjur Braendeland /* 2b482cd20SSjur Braendeland * Copyright (C) ST-Ericsson AB 2010 3b482cd20SSjur Braendeland * Author: Sjur Brendeland/sjur.brandeland@stericsson.com 4b482cd20SSjur Braendeland * License terms: GNU General Public License (GPL) version 2 5b482cd20SSjur Braendeland */ 6b482cd20SSjur Braendeland 7b31fa5baSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ 8b31fa5baSJoe Perches 9b482cd20SSjur Braendeland #include <linux/stddef.h> 10b482cd20SSjur Braendeland #include <linux/slab.h> 11b482cd20SSjur Braendeland #include <net/caif/caif_layer.h> 12b482cd20SSjur Braendeland #include <net/caif/cfsrvl.h> 13b482cd20SSjur Braendeland #include <net/caif/cfpkt.h> 14b482cd20SSjur Braendeland 15b482cd20SSjur Braendeland #define VEI_PAYLOAD 0x00 16b482cd20SSjur Braendeland #define VEI_CMD_BIT 0x80 17b482cd20SSjur Braendeland #define VEI_FLOW_OFF 0x81 18b482cd20SSjur Braendeland #define VEI_FLOW_ON 0x80 19b482cd20SSjur Braendeland #define VEI_SET_PIN 0x82 20441c793aSShan Wei 21b482cd20SSjur Braendeland #define container_obj(layr) container_of(layr, struct cfsrvl, layer) 22b482cd20SSjur Braendeland 23b482cd20SSjur Braendeland static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt); 24b482cd20SSjur Braendeland static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt); 25b482cd20SSjur Braendeland 26b482cd20SSjur Braendeland struct cflayer *cfvei_create(u8 channel_id, struct dev_info *dev_info) 27b482cd20SSjur Braendeland { 28b482cd20SSjur Braendeland struct cfsrvl *vei = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC); 29b482cd20SSjur Braendeland if (!vei) { 30b31fa5baSJoe Perches pr_warn("Out of memory\n"); 31b482cd20SSjur Braendeland return NULL; 32b482cd20SSjur Braendeland } 33b482cd20SSjur Braendeland caif_assert(offsetof(struct cfsrvl, layer) == 0); 34b482cd20SSjur Braendeland memset(vei, 0, sizeof(struct cfsrvl)); 35b1c74247SSjur Braendeland cfsrvl_init(vei, channel_id, dev_info, true); 36b482cd20SSjur Braendeland vei->layer.receive = cfvei_receive; 37b482cd20SSjur Braendeland vei->layer.transmit = cfvei_transmit; 38b482cd20SSjur Braendeland snprintf(vei->layer.name, CAIF_LAYER_NAME_SZ - 1, "vei%d", channel_id); 39b482cd20SSjur Braendeland return &vei->layer; 40b482cd20SSjur Braendeland } 41b482cd20SSjur Braendeland 42b482cd20SSjur Braendeland static int cfvei_receive(struct cflayer *layr, struct cfpkt *pkt) 43b482cd20SSjur Braendeland { 44b482cd20SSjur Braendeland u8 cmd; 45b482cd20SSjur Braendeland int ret; 46b482cd20SSjur Braendeland caif_assert(layr->up != NULL); 47b482cd20SSjur Braendeland caif_assert(layr->receive != NULL); 48b482cd20SSjur Braendeland caif_assert(layr->ctrlcmd != NULL); 49b482cd20SSjur Braendeland 50b482cd20SSjur Braendeland 51b482cd20SSjur Braendeland if (cfpkt_extr_head(pkt, &cmd, 1) < 0) { 52b31fa5baSJoe Perches pr_err("Packet is erroneous!\n"); 53b482cd20SSjur Braendeland cfpkt_destroy(pkt); 54b482cd20SSjur Braendeland return -EPROTO; 55b482cd20SSjur Braendeland } 56b482cd20SSjur Braendeland switch (cmd) { 57b482cd20SSjur Braendeland case VEI_PAYLOAD: 58b482cd20SSjur Braendeland ret = layr->up->receive(layr->up, pkt); 59b482cd20SSjur Braendeland return ret; 60b482cd20SSjur Braendeland case VEI_FLOW_OFF: 61b482cd20SSjur Braendeland layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0); 62b482cd20SSjur Braendeland cfpkt_destroy(pkt); 63b482cd20SSjur Braendeland return 0; 64b482cd20SSjur Braendeland case VEI_FLOW_ON: 65b482cd20SSjur Braendeland layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0); 66b482cd20SSjur Braendeland cfpkt_destroy(pkt); 67b482cd20SSjur Braendeland return 0; 68b482cd20SSjur Braendeland case VEI_SET_PIN: /* SET RS232 PIN */ 69b482cd20SSjur Braendeland cfpkt_destroy(pkt); 70b482cd20SSjur Braendeland return 0; 71b482cd20SSjur Braendeland default: /* SET RS232 PIN */ 72b31fa5baSJoe Perches pr_warn("Unknown VEI control packet %d (0x%x)!\n", cmd, cmd); 73b482cd20SSjur Braendeland cfpkt_destroy(pkt); 74b482cd20SSjur Braendeland return -EPROTO; 75b482cd20SSjur Braendeland } 76b482cd20SSjur Braendeland } 77b482cd20SSjur Braendeland 78b482cd20SSjur Braendeland static int cfvei_transmit(struct cflayer *layr, struct cfpkt *pkt) 79b482cd20SSjur Braendeland { 80b482cd20SSjur Braendeland u8 tmp = 0; 81b482cd20SSjur Braendeland struct caif_payload_info *info; 82b482cd20SSjur Braendeland int ret; 83b482cd20SSjur Braendeland struct cfsrvl *service = container_obj(layr); 84b482cd20SSjur Braendeland if (!cfsrvl_ready(service, &ret)) 85c85c2951Ssjur.brandeland@stericsson.com goto err; 86b482cd20SSjur Braendeland caif_assert(layr->dn != NULL); 87b482cd20SSjur Braendeland caif_assert(layr->dn->transmit != NULL); 88b482cd20SSjur Braendeland 89b482cd20SSjur Braendeland if (cfpkt_add_head(pkt, &tmp, 1) < 0) { 90b31fa5baSJoe Perches pr_err("Packet is erroneous!\n"); 91c85c2951Ssjur.brandeland@stericsson.com ret = -EPROTO; 92c85c2951Ssjur.brandeland@stericsson.com goto err; 93b482cd20SSjur Braendeland } 94b482cd20SSjur Braendeland 95b482cd20SSjur Braendeland /* Add info-> for MUX-layer to route the packet out. */ 96b482cd20SSjur Braendeland info = cfpkt_info(pkt); 97b482cd20SSjur Braendeland info->channel_id = service->layer.id; 98b482cd20SSjur Braendeland info->hdr_len = 1; 99b482cd20SSjur Braendeland info->dev_info = &service->dev_info; 1004dd820c0SSjur Brændeland return layr->dn->transmit(layr->dn, pkt); 101c85c2951Ssjur.brandeland@stericsson.com err: 102c85c2951Ssjur.brandeland@stericsson.com cfpkt_destroy(pkt); 103c85c2951Ssjur.brandeland@stericsson.com return ret; 104b482cd20SSjur Braendeland } 105