18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Author Karsten Keil <kkeil@novell.com> 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 2008 by Karsten Keil <kkeil@novell.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/gfp.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/mISDNhw.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic void 148c2ecf20Sopenharmony_cidchannel_bh(struct work_struct *ws) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci struct dchannel *dch = container_of(ws, struct dchannel, workq); 178c2ecf20Sopenharmony_ci struct sk_buff *skb; 188c2ecf20Sopenharmony_ci int err; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_RECVQUEUE, &dch->Flags)) { 218c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&dch->rqueue))) { 228c2ecf20Sopenharmony_ci if (likely(dch->dev.D.peer)) { 238c2ecf20Sopenharmony_ci err = dch->dev.D.recv(dch->dev.D.peer, skb); 248c2ecf20Sopenharmony_ci if (err) 258c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 268c2ecf20Sopenharmony_ci } else 278c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 288c2ecf20Sopenharmony_ci } 298c2ecf20Sopenharmony_ci } 308c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_PHCHANGE, &dch->Flags)) { 318c2ecf20Sopenharmony_ci if (dch->phfunc) 328c2ecf20Sopenharmony_ci dch->phfunc(dch); 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic void 378c2ecf20Sopenharmony_cibchannel_bh(struct work_struct *ws) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ws, struct bchannel, workq); 408c2ecf20Sopenharmony_ci struct sk_buff *skb; 418c2ecf20Sopenharmony_ci int err; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) { 448c2ecf20Sopenharmony_ci while ((skb = skb_dequeue(&bch->rqueue))) { 458c2ecf20Sopenharmony_ci bch->rcount--; 468c2ecf20Sopenharmony_ci if (likely(bch->ch.peer)) { 478c2ecf20Sopenharmony_ci err = bch->ch.recv(bch->ch.peer, skb); 488c2ecf20Sopenharmony_ci if (err) 498c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 508c2ecf20Sopenharmony_ci } else 518c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ciint 578c2ecf20Sopenharmony_cimISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci test_and_set_bit(FLG_HDLC, &ch->Flags); 608c2ecf20Sopenharmony_ci ch->maxlen = maxlen; 618c2ecf20Sopenharmony_ci ch->hw = NULL; 628c2ecf20Sopenharmony_ci ch->rx_skb = NULL; 638c2ecf20Sopenharmony_ci ch->tx_skb = NULL; 648c2ecf20Sopenharmony_ci ch->tx_idx = 0; 658c2ecf20Sopenharmony_ci ch->phfunc = phf; 668c2ecf20Sopenharmony_ci skb_queue_head_init(&ch->squeue); 678c2ecf20Sopenharmony_ci skb_queue_head_init(&ch->rqueue); 688c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ch->dev.bchannels); 698c2ecf20Sopenharmony_ci INIT_WORK(&ch->workq, dchannel_bh); 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDN_initdchannel); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciint 758c2ecf20Sopenharmony_cimISDN_initbchannel(struct bchannel *ch, unsigned short maxlen, 768c2ecf20Sopenharmony_ci unsigned short minlen) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci ch->Flags = 0; 798c2ecf20Sopenharmony_ci ch->minlen = minlen; 808c2ecf20Sopenharmony_ci ch->next_minlen = minlen; 818c2ecf20Sopenharmony_ci ch->init_minlen = minlen; 828c2ecf20Sopenharmony_ci ch->maxlen = maxlen; 838c2ecf20Sopenharmony_ci ch->next_maxlen = maxlen; 848c2ecf20Sopenharmony_ci ch->init_maxlen = maxlen; 858c2ecf20Sopenharmony_ci ch->hw = NULL; 868c2ecf20Sopenharmony_ci ch->rx_skb = NULL; 878c2ecf20Sopenharmony_ci ch->tx_skb = NULL; 888c2ecf20Sopenharmony_ci ch->tx_idx = 0; 898c2ecf20Sopenharmony_ci skb_queue_head_init(&ch->rqueue); 908c2ecf20Sopenharmony_ci ch->rcount = 0; 918c2ecf20Sopenharmony_ci ch->next_skb = NULL; 928c2ecf20Sopenharmony_ci INIT_WORK(&ch->workq, bchannel_bh); 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDN_initbchannel); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciint 988c2ecf20Sopenharmony_cimISDN_freedchannel(struct dchannel *ch) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci if (ch->tx_skb) { 1018c2ecf20Sopenharmony_ci dev_kfree_skb(ch->tx_skb); 1028c2ecf20Sopenharmony_ci ch->tx_skb = NULL; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci if (ch->rx_skb) { 1058c2ecf20Sopenharmony_ci dev_kfree_skb(ch->rx_skb); 1068c2ecf20Sopenharmony_ci ch->rx_skb = NULL; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci skb_queue_purge(&ch->squeue); 1098c2ecf20Sopenharmony_ci skb_queue_purge(&ch->rqueue); 1108c2ecf20Sopenharmony_ci flush_work(&ch->workq); 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDN_freedchannel); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_civoid 1168c2ecf20Sopenharmony_cimISDN_clear_bchannel(struct bchannel *ch) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci if (ch->tx_skb) { 1198c2ecf20Sopenharmony_ci dev_kfree_skb(ch->tx_skb); 1208c2ecf20Sopenharmony_ci ch->tx_skb = NULL; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci ch->tx_idx = 0; 1238c2ecf20Sopenharmony_ci if (ch->rx_skb) { 1248c2ecf20Sopenharmony_ci dev_kfree_skb(ch->rx_skb); 1258c2ecf20Sopenharmony_ci ch->rx_skb = NULL; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci if (ch->next_skb) { 1288c2ecf20Sopenharmony_ci dev_kfree_skb(ch->next_skb); 1298c2ecf20Sopenharmony_ci ch->next_skb = NULL; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); 1328c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); 1338c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &ch->Flags); 1348c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags); 1358c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags); 1368c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_RX_OFF, &ch->Flags); 1378c2ecf20Sopenharmony_ci ch->dropcnt = 0; 1388c2ecf20Sopenharmony_ci ch->minlen = ch->init_minlen; 1398c2ecf20Sopenharmony_ci ch->next_minlen = ch->init_minlen; 1408c2ecf20Sopenharmony_ci ch->maxlen = ch->init_maxlen; 1418c2ecf20Sopenharmony_ci ch->next_maxlen = ch->init_maxlen; 1428c2ecf20Sopenharmony_ci skb_queue_purge(&ch->rqueue); 1438c2ecf20Sopenharmony_ci ch->rcount = 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDN_clear_bchannel); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_civoid 1488c2ecf20Sopenharmony_cimISDN_freebchannel(struct bchannel *ch) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci cancel_work_sync(&ch->workq); 1518c2ecf20Sopenharmony_ci mISDN_clear_bchannel(ch); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDN_freebchannel); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ciint 1568c2ecf20Sopenharmony_cimISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci int ret = 0; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci switch (cq->op) { 1618c2ecf20Sopenharmony_ci case MISDN_CTRL_GETOP: 1628c2ecf20Sopenharmony_ci cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY | 1638c2ecf20Sopenharmony_ci MISDN_CTRL_RX_OFF; 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci case MISDN_CTRL_FILL_EMPTY: 1668c2ecf20Sopenharmony_ci if (cq->p1) { 1678c2ecf20Sopenharmony_ci memset(bch->fill, cq->p2 & 0xff, MISDN_BCH_FILL_SIZE); 1688c2ecf20Sopenharmony_ci test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); 1698c2ecf20Sopenharmony_ci } else { 1708c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case MISDN_CTRL_RX_OFF: 1748c2ecf20Sopenharmony_ci /* read back dropped byte count */ 1758c2ecf20Sopenharmony_ci cq->p2 = bch->dropcnt; 1768c2ecf20Sopenharmony_ci if (cq->p1) 1778c2ecf20Sopenharmony_ci test_and_set_bit(FLG_RX_OFF, &bch->Flags); 1788c2ecf20Sopenharmony_ci else 1798c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_RX_OFF, &bch->Flags); 1808c2ecf20Sopenharmony_ci bch->dropcnt = 0; 1818c2ecf20Sopenharmony_ci break; 1828c2ecf20Sopenharmony_ci case MISDN_CTRL_RX_BUFFER: 1838c2ecf20Sopenharmony_ci if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE) 1848c2ecf20Sopenharmony_ci bch->next_maxlen = cq->p2; 1858c2ecf20Sopenharmony_ci if (cq->p1 > MISDN_CTRL_RX_SIZE_IGNORE) 1868c2ecf20Sopenharmony_ci bch->next_minlen = cq->p1; 1878c2ecf20Sopenharmony_ci /* we return the old values */ 1888c2ecf20Sopenharmony_ci cq->p1 = bch->minlen; 1898c2ecf20Sopenharmony_ci cq->p2 = bch->maxlen; 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci default: 1928c2ecf20Sopenharmony_ci pr_info("mISDN unhandled control %x operation\n", cq->op); 1938c2ecf20Sopenharmony_ci ret = -EINVAL; 1948c2ecf20Sopenharmony_ci break; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci return ret; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(mISDN_ctrl_bchannel); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic inline u_int 2018c2ecf20Sopenharmony_ciget_sapi_tei(u_char *p) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci u_int sapi, tei; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci sapi = *p >> 2; 2068c2ecf20Sopenharmony_ci tei = p[1] >> 1; 2078c2ecf20Sopenharmony_ci return sapi | (tei << 8); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_civoid 2118c2ecf20Sopenharmony_cirecv_Dchannel(struct dchannel *dch) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct mISDNhead *hh; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (dch->rx_skb->len < 2) { /* at least 2 for sapi / tei */ 2168c2ecf20Sopenharmony_ci dev_kfree_skb(dch->rx_skb); 2178c2ecf20Sopenharmony_ci dch->rx_skb = NULL; 2188c2ecf20Sopenharmony_ci return; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci hh = mISDN_HEAD_P(dch->rx_skb); 2218c2ecf20Sopenharmony_ci hh->prim = PH_DATA_IND; 2228c2ecf20Sopenharmony_ci hh->id = get_sapi_tei(dch->rx_skb->data); 2238c2ecf20Sopenharmony_ci skb_queue_tail(&dch->rqueue, dch->rx_skb); 2248c2ecf20Sopenharmony_ci dch->rx_skb = NULL; 2258c2ecf20Sopenharmony_ci schedule_event(dch, FLG_RECVQUEUE); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(recv_Dchannel); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_civoid 2308c2ecf20Sopenharmony_cirecv_Echannel(struct dchannel *ech, struct dchannel *dch) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct mISDNhead *hh; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (ech->rx_skb->len < 2) { /* at least 2 for sapi / tei */ 2358c2ecf20Sopenharmony_ci dev_kfree_skb(ech->rx_skb); 2368c2ecf20Sopenharmony_ci ech->rx_skb = NULL; 2378c2ecf20Sopenharmony_ci return; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci hh = mISDN_HEAD_P(ech->rx_skb); 2408c2ecf20Sopenharmony_ci hh->prim = PH_DATA_E_IND; 2418c2ecf20Sopenharmony_ci hh->id = get_sapi_tei(ech->rx_skb->data); 2428c2ecf20Sopenharmony_ci skb_queue_tail(&dch->rqueue, ech->rx_skb); 2438c2ecf20Sopenharmony_ci ech->rx_skb = NULL; 2448c2ecf20Sopenharmony_ci schedule_event(dch, FLG_RECVQUEUE); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ciEXPORT_SYMBOL(recv_Echannel); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_civoid 2498c2ecf20Sopenharmony_cirecv_Bchannel(struct bchannel *bch, unsigned int id, bool force) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct mISDNhead *hh; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* if allocation did fail upper functions still may call us */ 2548c2ecf20Sopenharmony_ci if (unlikely(!bch->rx_skb)) 2558c2ecf20Sopenharmony_ci return; 2568c2ecf20Sopenharmony_ci if (unlikely(!bch->rx_skb->len)) { 2578c2ecf20Sopenharmony_ci /* we have no data to send - this may happen after recovery 2588c2ecf20Sopenharmony_ci * from overflow or too small allocation. 2598c2ecf20Sopenharmony_ci * We need to free the buffer here */ 2608c2ecf20Sopenharmony_ci dev_kfree_skb(bch->rx_skb); 2618c2ecf20Sopenharmony_ci bch->rx_skb = NULL; 2628c2ecf20Sopenharmony_ci } else { 2638c2ecf20Sopenharmony_ci if (test_bit(FLG_TRANSPARENT, &bch->Flags) && 2648c2ecf20Sopenharmony_ci (bch->rx_skb->len < bch->minlen) && !force) 2658c2ecf20Sopenharmony_ci return; 2668c2ecf20Sopenharmony_ci hh = mISDN_HEAD_P(bch->rx_skb); 2678c2ecf20Sopenharmony_ci hh->prim = PH_DATA_IND; 2688c2ecf20Sopenharmony_ci hh->id = id; 2698c2ecf20Sopenharmony_ci if (bch->rcount >= 64) { 2708c2ecf20Sopenharmony_ci printk(KERN_WARNING 2718c2ecf20Sopenharmony_ci "B%d receive queue overflow - flushing!\n", 2728c2ecf20Sopenharmony_ci bch->nr); 2738c2ecf20Sopenharmony_ci skb_queue_purge(&bch->rqueue); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci bch->rcount++; 2768c2ecf20Sopenharmony_ci skb_queue_tail(&bch->rqueue, bch->rx_skb); 2778c2ecf20Sopenharmony_ci bch->rx_skb = NULL; 2788c2ecf20Sopenharmony_ci schedule_event(bch, FLG_RECVQUEUE); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(recv_Bchannel); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_civoid 2848c2ecf20Sopenharmony_cirecv_Dchannel_skb(struct dchannel *dch, struct sk_buff *skb) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci skb_queue_tail(&dch->rqueue, skb); 2878c2ecf20Sopenharmony_ci schedule_event(dch, FLG_RECVQUEUE); 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(recv_Dchannel_skb); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_civoid 2928c2ecf20Sopenharmony_cirecv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci if (bch->rcount >= 64) { 2958c2ecf20Sopenharmony_ci printk(KERN_WARNING "B-channel %p receive queue overflow, " 2968c2ecf20Sopenharmony_ci "flushing!\n", bch); 2978c2ecf20Sopenharmony_ci skb_queue_purge(&bch->rqueue); 2988c2ecf20Sopenharmony_ci bch->rcount = 0; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci bch->rcount++; 3018c2ecf20Sopenharmony_ci skb_queue_tail(&bch->rqueue, skb); 3028c2ecf20Sopenharmony_ci schedule_event(bch, FLG_RECVQUEUE); 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(recv_Bchannel_skb); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void 3078c2ecf20Sopenharmony_ciconfirm_Dsend(struct dchannel *dch) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct sk_buff *skb; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(dch->tx_skb), 3128c2ecf20Sopenharmony_ci 0, NULL, GFP_ATOMIC); 3138c2ecf20Sopenharmony_ci if (!skb) { 3148c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: no skb id %x\n", __func__, 3158c2ecf20Sopenharmony_ci mISDN_HEAD_ID(dch->tx_skb)); 3168c2ecf20Sopenharmony_ci return; 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci skb_queue_tail(&dch->rqueue, skb); 3198c2ecf20Sopenharmony_ci schedule_event(dch, FLG_RECVQUEUE); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ciint 3238c2ecf20Sopenharmony_ciget_next_dframe(struct dchannel *dch) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci dch->tx_idx = 0; 3268c2ecf20Sopenharmony_ci dch->tx_skb = skb_dequeue(&dch->squeue); 3278c2ecf20Sopenharmony_ci if (dch->tx_skb) { 3288c2ecf20Sopenharmony_ci confirm_Dsend(dch); 3298c2ecf20Sopenharmony_ci return 1; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci dch->tx_skb = NULL; 3328c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(get_next_dframe); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_cistatic void 3388c2ecf20Sopenharmony_ciconfirm_Bsend(struct bchannel *bch) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct sk_buff *skb; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci if (bch->rcount >= 64) { 3438c2ecf20Sopenharmony_ci printk(KERN_WARNING "B-channel %p receive queue overflow, " 3448c2ecf20Sopenharmony_ci "flushing!\n", bch); 3458c2ecf20Sopenharmony_ci skb_queue_purge(&bch->rqueue); 3468c2ecf20Sopenharmony_ci bch->rcount = 0; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb), 3498c2ecf20Sopenharmony_ci 0, NULL, GFP_ATOMIC); 3508c2ecf20Sopenharmony_ci if (!skb) { 3518c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: no skb id %x\n", __func__, 3528c2ecf20Sopenharmony_ci mISDN_HEAD_ID(bch->tx_skb)); 3538c2ecf20Sopenharmony_ci return; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci bch->rcount++; 3568c2ecf20Sopenharmony_ci skb_queue_tail(&bch->rqueue, skb); 3578c2ecf20Sopenharmony_ci schedule_event(bch, FLG_RECVQUEUE); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ciint 3618c2ecf20Sopenharmony_ciget_next_bframe(struct bchannel *bch) 3628c2ecf20Sopenharmony_ci{ 3638c2ecf20Sopenharmony_ci bch->tx_idx = 0; 3648c2ecf20Sopenharmony_ci if (test_bit(FLG_TX_NEXT, &bch->Flags)) { 3658c2ecf20Sopenharmony_ci bch->tx_skb = bch->next_skb; 3668c2ecf20Sopenharmony_ci if (bch->tx_skb) { 3678c2ecf20Sopenharmony_ci bch->next_skb = NULL; 3688c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); 3698c2ecf20Sopenharmony_ci /* confirm imediately to allow next data */ 3708c2ecf20Sopenharmony_ci confirm_Bsend(bch); 3718c2ecf20Sopenharmony_ci return 1; 3728c2ecf20Sopenharmony_ci } else { 3738c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); 3748c2ecf20Sopenharmony_ci printk(KERN_WARNING "B TX_NEXT without skb\n"); 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci bch->tx_skb = NULL; 3788c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &bch->Flags); 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(get_next_bframe); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_civoid 3848c2ecf20Sopenharmony_ciqueue_ch_frame(struct mISDNchannel *ch, u_int pr, int id, struct sk_buff *skb) 3858c2ecf20Sopenharmony_ci{ 3868c2ecf20Sopenharmony_ci struct mISDNhead *hh; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (!skb) { 3898c2ecf20Sopenharmony_ci _queue_data(ch, pr, id, 0, NULL, GFP_ATOMIC); 3908c2ecf20Sopenharmony_ci } else { 3918c2ecf20Sopenharmony_ci if (ch->peer) { 3928c2ecf20Sopenharmony_ci hh = mISDN_HEAD_P(skb); 3938c2ecf20Sopenharmony_ci hh->prim = pr; 3948c2ecf20Sopenharmony_ci hh->id = id; 3958c2ecf20Sopenharmony_ci if (!ch->recv(ch->peer, skb)) 3968c2ecf20Sopenharmony_ci return; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ciEXPORT_SYMBOL(queue_ch_frame); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ciint 4048c2ecf20Sopenharmony_cidchannel_senddata(struct dchannel *ch, struct sk_buff *skb) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci /* check oversize */ 4078c2ecf20Sopenharmony_ci if (skb->len <= 0) { 4088c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: skb too small\n", __func__); 4098c2ecf20Sopenharmony_ci return -EINVAL; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci if (skb->len > ch->maxlen) { 4128c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: skb too large(%d/%d)\n", 4138c2ecf20Sopenharmony_ci __func__, skb->len, ch->maxlen); 4148c2ecf20Sopenharmony_ci return -EINVAL; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci /* HW lock must be obtained */ 4178c2ecf20Sopenharmony_ci if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { 4188c2ecf20Sopenharmony_ci skb_queue_tail(&ch->squeue, skb); 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci } else { 4218c2ecf20Sopenharmony_ci /* write to fifo */ 4228c2ecf20Sopenharmony_ci ch->tx_skb = skb; 4238c2ecf20Sopenharmony_ci ch->tx_idx = 0; 4248c2ecf20Sopenharmony_ci return 1; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci} 4278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dchannel_senddata); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ciint 4308c2ecf20Sopenharmony_cibchannel_senddata(struct bchannel *ch, struct sk_buff *skb) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* check oversize */ 4348c2ecf20Sopenharmony_ci if (skb->len <= 0) { 4358c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: skb too small\n", __func__); 4368c2ecf20Sopenharmony_ci return -EINVAL; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci if (skb->len > ch->maxlen) { 4398c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: skb too large(%d/%d)\n", 4408c2ecf20Sopenharmony_ci __func__, skb->len, ch->maxlen); 4418c2ecf20Sopenharmony_ci return -EINVAL; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci /* HW lock must be obtained */ 4448c2ecf20Sopenharmony_ci /* check for pending next_skb */ 4458c2ecf20Sopenharmony_ci if (ch->next_skb) { 4468c2ecf20Sopenharmony_ci printk(KERN_WARNING 4478c2ecf20Sopenharmony_ci "%s: next_skb exist ERROR (skb->len=%d next_skb->len=%d)\n", 4488c2ecf20Sopenharmony_ci __func__, skb->len, ch->next_skb->len); 4498c2ecf20Sopenharmony_ci return -EBUSY; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci if (test_and_set_bit(FLG_TX_BUSY, &ch->Flags)) { 4528c2ecf20Sopenharmony_ci test_and_set_bit(FLG_TX_NEXT, &ch->Flags); 4538c2ecf20Sopenharmony_ci ch->next_skb = skb; 4548c2ecf20Sopenharmony_ci return 0; 4558c2ecf20Sopenharmony_ci } else { 4568c2ecf20Sopenharmony_ci /* write to fifo */ 4578c2ecf20Sopenharmony_ci ch->tx_skb = skb; 4588c2ecf20Sopenharmony_ci ch->tx_idx = 0; 4598c2ecf20Sopenharmony_ci confirm_Bsend(ch); 4608c2ecf20Sopenharmony_ci return 1; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bchannel_senddata); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci/* The function allocates a new receive skb on demand with a size for the 4668c2ecf20Sopenharmony_ci * requirements of the current protocol. It returns the tailroom of the 4678c2ecf20Sopenharmony_ci * receive skb or an error. 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_ciint 4708c2ecf20Sopenharmony_cibchannel_get_rxbuf(struct bchannel *bch, int reqlen) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci int len; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (bch->rx_skb) { 4758c2ecf20Sopenharmony_ci len = skb_tailroom(bch->rx_skb); 4768c2ecf20Sopenharmony_ci if (len < reqlen) { 4778c2ecf20Sopenharmony_ci pr_warn("B%d no space for %d (only %d) bytes\n", 4788c2ecf20Sopenharmony_ci bch->nr, reqlen, len); 4798c2ecf20Sopenharmony_ci if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { 4808c2ecf20Sopenharmony_ci /* send what we have now and try a new buffer */ 4818c2ecf20Sopenharmony_ci recv_Bchannel(bch, 0, true); 4828c2ecf20Sopenharmony_ci } else { 4838c2ecf20Sopenharmony_ci /* on HDLC we have to drop too big frames */ 4848c2ecf20Sopenharmony_ci return -EMSGSIZE; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci } else { 4878c2ecf20Sopenharmony_ci return len; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci /* update current min/max length first */ 4918c2ecf20Sopenharmony_ci if (unlikely(bch->maxlen != bch->next_maxlen)) 4928c2ecf20Sopenharmony_ci bch->maxlen = bch->next_maxlen; 4938c2ecf20Sopenharmony_ci if (unlikely(bch->minlen != bch->next_minlen)) 4948c2ecf20Sopenharmony_ci bch->minlen = bch->next_minlen; 4958c2ecf20Sopenharmony_ci if (unlikely(reqlen > bch->maxlen)) 4968c2ecf20Sopenharmony_ci return -EMSGSIZE; 4978c2ecf20Sopenharmony_ci if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { 4988c2ecf20Sopenharmony_ci if (reqlen >= bch->minlen) { 4998c2ecf20Sopenharmony_ci len = reqlen; 5008c2ecf20Sopenharmony_ci } else { 5018c2ecf20Sopenharmony_ci len = 2 * bch->minlen; 5028c2ecf20Sopenharmony_ci if (len > bch->maxlen) 5038c2ecf20Sopenharmony_ci len = bch->maxlen; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci } else { 5068c2ecf20Sopenharmony_ci /* with HDLC we do not know the length yet */ 5078c2ecf20Sopenharmony_ci len = bch->maxlen; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC); 5108c2ecf20Sopenharmony_ci if (!bch->rx_skb) { 5118c2ecf20Sopenharmony_ci pr_warn("B%d receive no memory for %d bytes\n", bch->nr, len); 5128c2ecf20Sopenharmony_ci len = -ENOMEM; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci return len; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bchannel_get_rxbuf); 517