/* * Copyright (C) ST-Ericsson AB 2010 * Author: Sjur Brendeland * License terms: GNU General Public License (GPL) version 2 */ #define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__ #include #include #include #include #include #include #define container_obj(layr) ((struct cfserl *) layr) #define CFSERL_STX 0x02 #define SERIAL_MINIUM_PACKET_SIZE 4 #define SERIAL_MAX_FRAMESIZE 4096 struct cfserl { struct cflayer layer; struct cfpkt *incomplete_frm; /* Protects parallel processing of incoming packets */ spinlock_t sync; bool usestx; }; static int cfserl_receive(struct cflayer *layr, struct cfpkt *pkt); static int cfserl_transmit(struct cflayer *layr, struct cfpkt *pkt); static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, int phyid); struct cflayer *cfserl_create(int instance, bool use_stx) { struct cfserl *this = kzalloc(sizeof(struct cfserl), GFP_ATOMIC); if (!this) return NULL; caif_assert(offsetof(struct cfserl, layer) == 0); this->layer.receive = cfserl_receive; this->layer.transmit = cfserl_transmit; this->layer.ctrlcmd = cfserl_ctrlcmd; this->usestx = use_stx; spin_lock_init(&this->sync); snprintf(this->layer.name, CAIF_LAYER_NAME_SZ, "ser1"); return &this->layer; } static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt) { struct cfserl *layr = container_obj(l); u16 pkt_len; struct cfpkt *pkt = NULL; struct cfpkt *tail_pkt = NULL; u8 tmp8; u16 tmp; u8 stx = CFSERL_STX; int ret; u16 expectlen = 0; caif_assert(newpkt != NULL); spin_lock(&layr->sync); if (layr->incomplete_frm != NULL) { layr->incomplete_frm = cfpkt_append(layr->incomplete_frm, newpkt, expectlen); pkt = layr->incomplete_frm; if (pkt == NULL) { spin_unlock(&layr->sync); return -ENOMEM; } } else { pkt = newpkt; } layr->incomplete_frm = NULL; do { /* Search for STX at start of pkt if STX is used */ if (layr->usestx) { cfpkt_extr_head(pkt, &tmp8, 1); if (tmp8 != CFSERL_STX) { while (cfpkt_more(pkt) && tmp8 != CFSERL_STX) { cfpkt_extr_head(pkt, &tmp8, 1); } if (!cfpkt_more(pkt)) { cfpkt_destroy(pkt); layr->incomplete_frm = NULL; spin_unlock(&layr->sync); return -EPROTO; } } } pkt_len = cfpkt_getlen(pkt); /* * pkt_len is the accumulated length of the packet data * we have received so far. * Exit if frame doesn't hold length. */ if (pkt_len < 2) { if (layr->usestx) cfpkt_add_head(pkt, &stx, 1); layr->incomplete_frm = pkt; spin_unlock(&layr->sync); return 0; } /* * Find length of frame. * expectlen is the length we need for a full frame. */ cfpkt_peek_head(pkt, &tmp, 2); expectlen = le16_to_cpu(tmp) + 2; /* * Frame error handling */ if (expectlen < SERIAL_MINIUM_PACKET_SIZE || expectlen > SERIAL_MAX_FRAMESIZE) { if (!layr->usestx) { if (pkt != NULL) cfpkt_destroy(pkt); layr->incomplete_frm = NULL; expectlen = 0; spin_unlock(&layr->sync); return -EPROTO; } continue; } if (pkt_len < expectlen) { /* Too little received data */ if (layr->usestx) cfpkt_add_head(pkt, &stx, 1); layr->incomplete_frm = pkt; spin_unlock(&layr->sync); return 0; } /* * Enough data for at least one frame. * Split the frame, if too long */ if (pkt_len > expectlen) tail_pkt = cfpkt_split(pkt, expectlen); else tail_pkt = NULL; /* Send the first part of packet upwards.*/ spin_unlock(&layr->sync); ret = layr->layer.up->receive(layr->layer.up, pkt); spin_lock(&layr->sync); if (ret == -EILSEQ) { if (layr->usestx) { if (tail_pkt != NULL) pkt = cfpkt_append(pkt, tail_pkt, 0); /* Start search for next STX if frame failed */ continue; } else { cfpkt_destroy(pkt); pkt = NULL; } } pkt = tail_pkt; } while (pkt != NULL); spin_unlock(&layr->sync); return 0; } static int cfserl_transmit(struct cflayer *layer, struct cfpkt *newpkt) { struct cfserl *layr = container_obj(layer); u8 tmp8 = CFSERL_STX; if (layr->usestx) cfpkt_add_head(newpkt, &tmp8, 1); return layer->dn->transmit(layer->dn, newpkt); } static void cfserl_ctrlcmd(struct cflayer *layr, enum caif_ctrlcmd ctrl, int phyid) { layr->up->ctrlcmd(layr->up, ctrl, phyid); } a>3852logplain -rw-r--r--adb.h1092logplain -rw-r--r--adfs_fs.h888logplain -rw-r--r--affs_hardblocks.h1481logplain -rw-r--r--agpgart.h4001logplain -rw-r--r--aio_abi.h3176logplain -rw-r--r--am437x-vpfe.h3618logplain d---------android70logplain -rw-r--r--apm_bios.h3634logplain -rw-r--r--arcfb.h150logplain -rw-r--r--atalk.h975logplain -rw-r--r--atm.h7874logplain -rw-r--r--atm_eni.h585logplain -rw-r--r--atm_he.h343logplain -rw-r--r--atm_idt77105.h892logplain -rw-r--r--atm_nicstar.h1215logplain -rw-r--r--atm_tcp.h1574logplain -rw-r--r--atm_zatm.h1477logplain -rw-r--r--atmapi.h889logplain -rw-r--r--atmarp.h1233logplain -rw-r--r--atmbr2684.h3208logplain -rw-r--r--atmclip.h513logplain -rw-r--r--atmdev.h7636logplain -rw-r--r--atmioc.h1583logplain -rw-r--r--atmlec.h2318logplain -rw-r--r--atmmpc.h4163logplain -rw-r--r--atmppp.h576logplain -rw-r--r--atmsap.h4907logplain -rw-r--r--atmsvc.h1790logplain -rw-r--r--audit.h19048logplain -rw-r--r--auto_dev-ioctl.h5093logplain -rw-r--r--auto_fs.h2260logplain -rw-r--r--auto_fs4.h4010logplain -rw-r--r--auxvec.h1448logplain -rw-r--r--ax25.h2761logplain -rw-r--r--b1lli.h1654logplain -rw-r--r--batman_adv.h8606logplain -rw-r--r--baycom.h820logplain -rw-r--r--bcache.h8237logplain -rw-r--r--bcm933xx_hcs.h356logplain -rw-r--r--bfs_fs.h1830logplain -rw-r--r--binfmts.h580logplain -rw-r--r--blkpg.h1620logplain -rw-r--r--blktrace_api.h4505logplain -rw-r--r--blkzoned.h5105logplain -rw-r--r--bpf.h18228logplain -rw-r--r--bpf_common.h1245logplain -rw-r--r--bpf_perf_event.h483logplain -rw-r--r--bpqether.h918logplain -rw-r--r--bsg.h2446logplain -rw-r--r--bt-bmc.h523logplain -rw-r--r--btrfs.h25922logplain -rw-r--r--btrfs_tree.h25015logplain d---------byteorder117logplain d---------caif112logplain -rw-r--r--can.h7808logplain d---------can204logplain -rw-r--r--capability.h11387logplain -rw-r--r--capi.h3094logplain -rw-r--r--cciss_defs.h3218logplain -rw-r--r--cciss_ioctl.h2727logplain -rw-r--r--cdrom.h28839logplain -rw-r--r--cec-funcs.h54188logplain -rw-r--r--cec.h37095logplain -rw-r--r--cgroupstats.h2155logplain -rw-r--r--chio.h5288logplain d---------cifs40logplain -rw-r--r--cm4000_cs.h1758logplain -rw-r--r--cn_proc.h3285logplain -rw-r--r--coda.h17682logplain -rw-r--r--coda_psdev.h735logplain -rw-r--r--coff.h12413logplain -rw-r--r--connector.h2204logplain -rw-r--r--const.h673logplain -rw-r--r--coresight-stm.h611logplain -rw-r--r--cramfs_fs.h2764logplain -rw-r--r--cryptouser.h3336logplain -rw-r--r--cuda.h857logplain -rw-r--r--cyclades.h17060logplain -rw-r--r--cycx_cfm.h2926logplain -rw-r--r--dcbnl.h24849logplain -rw-r--r--dccp.h6384logplain -rw-r--r--devlink.h4465logplain -rw-r--r--dlm.h2505logplain -rw-r--r--dlm_device.h2536logplain -rw-r--r--dlm_netlink.h1064logplain -rw-r--r--dlm_plock.h846logplain -rw-r--r--dlmconstants.h5017logplain -rw-r--r--dm-ioctl.h10703logplain -rw-r--r--dm-log-userspace.h15126logplain -rw-r--r--dma-buf.h1295logplain -rw-r--r--dn.h4579logplain -rw-r--r--dqblk_xfs.h8934logplain d---------dvb310logplain -rw-r--r--edd.h5556logplain -rw-r--r--efs_fs_sb.h2164logplain -rw-r--r--elf-em.h2166logplain -rw-r--r--elf-fdpic.h1075logplain