int msm_bam_dmux_open(uint32_t id, void *priv, void (*receive_cb)(void *, struct sk_buff *), void (*write_done)(void *, struct sk_buff *)) { struct bam_mux_hdr *hdr; unsigned long flags; int rc = 0; DBG("%s: opening ch %d\n", __func__, id); if (!bam_mux_initialized) return -ENODEV; if (id >= BAM_DMUX_NUM_CHANNELS) return -EINVAL; hdr = kmalloc(sizeof(struct bam_mux_hdr), GFP_KERNEL); if (hdr == NULL) { pr_err("%s: hdr kmalloc failed. ch: %d\n", __func__, id); return -ENOMEM; } spin_lock_irqsave(&bam_ch[id].lock, flags); if (bam_ch_is_open(id)) { DBG("%s: Already opened %d\n", __func__, id); spin_unlock_irqrestore(&bam_ch[id].lock, flags); kfree(hdr); goto open_done; } if (!bam_ch_is_remote_open(id)) { DBG("%s: Remote not open; ch: %d\n", __func__, id); spin_unlock_irqrestore(&bam_ch[id].lock, flags); kfree(hdr); rc = -ENODEV; goto open_done; } bam_ch[id].receive_cb = receive_cb; bam_ch[id].write_done = write_done; bam_ch[id].priv = priv; bam_ch[id].status |= BAM_CH_LOCAL_OPEN; spin_unlock_irqrestore(&bam_ch[id].lock, flags); hdr->magic_num = BAM_MUX_HDR_MAGIC_NO; hdr->cmd = BAM_MUX_HDR_CMD_OPEN; hdr->reserved = 0; hdr->ch_id = id; hdr->pkt_len = 0; hdr->pad_len = 0; rc = bam_mux_write_cmd((void *)hdr, sizeof(struct bam_mux_hdr)); open_done: DBG("%s: opened ch %d\n", __func__, id); return rc; }
int msm_bam_dmux_write(uint32_t id, struct sk_buff *skb) { int rc = 0; struct bam_mux_hdr *hdr; unsigned long flags; struct sk_buff *new_skb = NULL; dma_addr_t dma_address; struct tx_pkt_info *pkt; if (id >= BAM_DMUX_NUM_CHANNELS) return -EINVAL; if (!skb) return -EINVAL; if (!bam_mux_initialized) return -ENODEV; DBG("%s: writing to ch %d len %d\n", __func__, id, skb->len); spin_lock_irqsave(&bam_ch[id].lock, flags); if (!bam_ch_is_open(id)) { spin_unlock_irqrestore(&bam_ch[id].lock, flags); pr_err("%s: port not open: %d\n", __func__, bam_ch[id].status); return -ENODEV; } spin_unlock_irqrestore(&bam_ch[id].lock, flags); spin_lock_irqsave(&bam_mux_write_lock, flags); /* if skb do not have any tailroom for padding, copy the skb into a new expanded skb */ if ((skb->len & 0x3) && (skb_tailroom(skb) < (4 - (skb->len & 0x3)))) { /* revisit, probably dev_alloc_skb and memcpy is effecient */ new_skb = skb_copy_expand(skb, skb_headroom(skb), 4 - (skb->len & 0x3), GFP_ATOMIC); if (new_skb == NULL) { pr_err("%s: cannot allocate skb\n", __func__); rc = -ENOMEM; goto write_done; } dev_kfree_skb_any(skb); skb = new_skb; DBG_INC_WRITE_CPY(skb->len); } hdr = (struct bam_mux_hdr *)skb_push(skb, sizeof(struct bam_mux_hdr)); /* caller should allocate for hdr and padding hdr is fine, padding is tricky */ hdr->magic_num = BAM_MUX_HDR_MAGIC_NO; hdr->cmd = BAM_MUX_HDR_CMD_DATA; hdr->reserved = 0; hdr->ch_id = id; hdr->pkt_len = skb->len - sizeof(struct bam_mux_hdr); if (skb->len & 0x3) skb_put(skb, 4 - (skb->len & 0x3)); hdr->pad_len = skb->len - (sizeof(struct bam_mux_hdr) + hdr->pkt_len); DBG("%s: data %p, tail %p skb len %d pkt len %d pad len %d\n", __func__, skb->data, skb->tail, skb->len, hdr->pkt_len, hdr->pad_len); pkt = kmalloc(sizeof(struct tx_pkt_info), GFP_ATOMIC); if (pkt == NULL) { pr_err("%s: mem alloc for tx_pkt_info failed\n", __func__); if (new_skb) dev_kfree_skb_any(new_skb); rc = -ENOMEM; goto write_done; } dma_address = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE); if (!dma_address) { pr_err("%s: dma_map_single() failed\n", __func__); if (new_skb) dev_kfree_skb_any(new_skb); kfree(pkt); rc = -ENOMEM; goto write_done; } pkt->skb = skb; pkt->dma_address = dma_address; pkt->is_cmd = 0; spin_unlock_irqrestore(&bam_mux_write_lock, flags); rc = sps_transfer_one(bam_tx_pipe, dma_address, skb->len, pkt, SPS_IOVEC_FLAG_INT | SPS_IOVEC_FLAG_EOT); return rc; write_done: spin_unlock_irqrestore(&bam_mux_write_lock, flags); return rc; }