18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* hfcsusb.c 38c2ecf20Sopenharmony_ci * mISDN driver for Colognechip HFC-S USB chip 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2001 by Peter Sprenger (sprenger@moving-bytes.de) 68c2ecf20Sopenharmony_ci * Copyright 2008 by Martin Bachem (info@bachem-it.com) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * module params 98c2ecf20Sopenharmony_ci * debug=<n>, default=0, with n=0xHHHHGGGG 108c2ecf20Sopenharmony_ci * H - l1 driver flags described in hfcsusb.h 118c2ecf20Sopenharmony_ci * G - common mISDN debug flags described at mISDNhw.h 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * poll=<n>, default 128 148c2ecf20Sopenharmony_ci * n : burst size of PH_DATA_IND at transparent rx data 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Revision: 0.3.3 (socket), 2008-11-05 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/module.h> 208c2ecf20Sopenharmony_ci#include <linux/delay.h> 218c2ecf20Sopenharmony_ci#include <linux/usb.h> 228c2ecf20Sopenharmony_ci#include <linux/mISDNhw.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include "hfcsusb.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic unsigned int debug; 278c2ecf20Sopenharmony_cistatic int poll = DEFAULT_TRANSP_BURST_SZ; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic LIST_HEAD(HFClist); 308c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(HFClock); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciMODULE_AUTHOR("Martin Bachem"); 348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 358c2ecf20Sopenharmony_cimodule_param(debug, uint, S_IRUGO | S_IWUSR); 368c2ecf20Sopenharmony_cimodule_param(poll, int, 0); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic int hfcsusb_cnt; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* some function prototypes */ 418c2ecf20Sopenharmony_cistatic void hfcsusb_ph_command(struct hfcsusb *hw, u_char command); 428c2ecf20Sopenharmony_cistatic void release_hw(struct hfcsusb *hw); 438c2ecf20Sopenharmony_cistatic void reset_hfcsusb(struct hfcsusb *hw); 448c2ecf20Sopenharmony_cistatic void setPortMode(struct hfcsusb *hw); 458c2ecf20Sopenharmony_cistatic void hfcsusb_start_endpoint(struct hfcsusb *hw, int channel); 468c2ecf20Sopenharmony_cistatic void hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel); 478c2ecf20Sopenharmony_cistatic int hfcsusb_setup_bch(struct bchannel *bch, int protocol); 488c2ecf20Sopenharmony_cistatic void deactivate_bchannel(struct bchannel *bch); 498c2ecf20Sopenharmony_cistatic int hfcsusb_ph_info(struct hfcsusb *hw); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* start next background transfer for control channel */ 528c2ecf20Sopenharmony_cistatic void 538c2ecf20Sopenharmony_cictrl_start_transfer(struct hfcsusb *hw) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 568c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (hw->ctrl_cnt) { 598c2ecf20Sopenharmony_ci hw->ctrl_urb->pipe = hw->ctrl_out_pipe; 608c2ecf20Sopenharmony_ci hw->ctrl_urb->setup_packet = (u_char *)&hw->ctrl_write; 618c2ecf20Sopenharmony_ci hw->ctrl_urb->transfer_buffer = NULL; 628c2ecf20Sopenharmony_ci hw->ctrl_urb->transfer_buffer_length = 0; 638c2ecf20Sopenharmony_ci hw->ctrl_write.wIndex = 648c2ecf20Sopenharmony_ci cpu_to_le16(hw->ctrl_buff[hw->ctrl_out_idx].hfcs_reg); 658c2ecf20Sopenharmony_ci hw->ctrl_write.wValue = 668c2ecf20Sopenharmony_ci cpu_to_le16(hw->ctrl_buff[hw->ctrl_out_idx].reg_val); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci usb_submit_urb(hw->ctrl_urb, GFP_ATOMIC); 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* 738c2ecf20Sopenharmony_ci * queue a control transfer request to write HFC-S USB 748c2ecf20Sopenharmony_ci * chip register using CTRL resuest queue 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_cistatic int write_reg(struct hfcsusb *hw, __u8 reg, __u8 val) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct ctrl_buf *buf; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 818c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s reg(0x%02x) val(0x%02x)\n", 828c2ecf20Sopenharmony_ci hw->name, __func__, reg, val); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci spin_lock(&hw->ctrl_lock); 858c2ecf20Sopenharmony_ci if (hw->ctrl_cnt >= HFC_CTRL_BUFSIZE) { 868c2ecf20Sopenharmony_ci spin_unlock(&hw->ctrl_lock); 878c2ecf20Sopenharmony_ci return 1; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci buf = &hw->ctrl_buff[hw->ctrl_in_idx]; 908c2ecf20Sopenharmony_ci buf->hfcs_reg = reg; 918c2ecf20Sopenharmony_ci buf->reg_val = val; 928c2ecf20Sopenharmony_ci if (++hw->ctrl_in_idx >= HFC_CTRL_BUFSIZE) 938c2ecf20Sopenharmony_ci hw->ctrl_in_idx = 0; 948c2ecf20Sopenharmony_ci if (++hw->ctrl_cnt == 1) 958c2ecf20Sopenharmony_ci ctrl_start_transfer(hw); 968c2ecf20Sopenharmony_ci spin_unlock(&hw->ctrl_lock); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci return 0; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* control completion routine handling background control cmds */ 1028c2ecf20Sopenharmony_cistatic void 1038c2ecf20Sopenharmony_cictrl_complete(struct urb *urb) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct hfcsusb *hw = (struct hfcsusb *) urb->context; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 1088c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci urb->dev = hw->dev; 1118c2ecf20Sopenharmony_ci if (hw->ctrl_cnt) { 1128c2ecf20Sopenharmony_ci hw->ctrl_cnt--; /* decrement actual count */ 1138c2ecf20Sopenharmony_ci if (++hw->ctrl_out_idx >= HFC_CTRL_BUFSIZE) 1148c2ecf20Sopenharmony_ci hw->ctrl_out_idx = 0; /* pointer wrap */ 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci ctrl_start_transfer(hw); /* start next transfer */ 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* handle LED bits */ 1218c2ecf20Sopenharmony_cistatic void 1228c2ecf20Sopenharmony_ciset_led_bit(struct hfcsusb *hw, signed short led_bits, int set_on) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci if (set_on) { 1258c2ecf20Sopenharmony_ci if (led_bits < 0) 1268c2ecf20Sopenharmony_ci hw->led_state &= ~abs(led_bits); 1278c2ecf20Sopenharmony_ci else 1288c2ecf20Sopenharmony_ci hw->led_state |= led_bits; 1298c2ecf20Sopenharmony_ci } else { 1308c2ecf20Sopenharmony_ci if (led_bits < 0) 1318c2ecf20Sopenharmony_ci hw->led_state |= abs(led_bits); 1328c2ecf20Sopenharmony_ci else 1338c2ecf20Sopenharmony_ci hw->led_state &= ~led_bits; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* handle LED requests */ 1388c2ecf20Sopenharmony_cistatic void 1398c2ecf20Sopenharmony_cihandle_led(struct hfcsusb *hw, int event) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct hfcsusb_vdata *driver_info = (struct hfcsusb_vdata *) 1428c2ecf20Sopenharmony_ci hfcsusb_idtab[hw->vend_idx].driver_info; 1438c2ecf20Sopenharmony_ci __u8 tmpled; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci if (driver_info->led_scheme == LED_OFF) 1468c2ecf20Sopenharmony_ci return; 1478c2ecf20Sopenharmony_ci tmpled = hw->led_state; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci switch (event) { 1508c2ecf20Sopenharmony_ci case LED_POWER_ON: 1518c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[0], 1); 1528c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[1], 0); 1538c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[2], 0); 1548c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[3], 0); 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci case LED_POWER_OFF: 1578c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[0], 0); 1588c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[1], 0); 1598c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[2], 0); 1608c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[3], 0); 1618c2ecf20Sopenharmony_ci break; 1628c2ecf20Sopenharmony_ci case LED_S0_ON: 1638c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[1], 1); 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci case LED_S0_OFF: 1668c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[1], 0); 1678c2ecf20Sopenharmony_ci break; 1688c2ecf20Sopenharmony_ci case LED_B1_ON: 1698c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[2], 1); 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci case LED_B1_OFF: 1728c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[2], 0); 1738c2ecf20Sopenharmony_ci break; 1748c2ecf20Sopenharmony_ci case LED_B2_ON: 1758c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[3], 1); 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci case LED_B2_OFF: 1788c2ecf20Sopenharmony_ci set_led_bit(hw, driver_info->led_bits[3], 0); 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (hw->led_state != tmpled) { 1838c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 1848c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s reg(0x%02x) val(x%02x)\n", 1858c2ecf20Sopenharmony_ci hw->name, __func__, 1868c2ecf20Sopenharmony_ci HFCUSB_P_DATA, hw->led_state); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_P_DATA, hw->led_state); 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * Layer2 -> Layer 1 Bchannel data 1948c2ecf20Sopenharmony_ci */ 1958c2ecf20Sopenharmony_cistatic int 1968c2ecf20Sopenharmony_cihfcusb_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 1998c2ecf20Sopenharmony_ci struct hfcsusb *hw = bch->hw; 2008c2ecf20Sopenharmony_ci int ret = -EINVAL; 2018c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 2028c2ecf20Sopenharmony_ci u_long flags; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 2058c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci switch (hh->prim) { 2088c2ecf20Sopenharmony_ci case PH_DATA_REQ: 2098c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 2108c2ecf20Sopenharmony_ci ret = bchannel_senddata(bch, skb); 2118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 2128c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 2138c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s PH_DATA_REQ ret(%i)\n", 2148c2ecf20Sopenharmony_ci hw->name, __func__, ret); 2158c2ecf20Sopenharmony_ci if (ret > 0) 2168c2ecf20Sopenharmony_ci ret = 0; 2178c2ecf20Sopenharmony_ci return ret; 2188c2ecf20Sopenharmony_ci case PH_ACTIVATE_REQ: 2198c2ecf20Sopenharmony_ci if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { 2208c2ecf20Sopenharmony_ci hfcsusb_start_endpoint(hw, bch->nr - 1); 2218c2ecf20Sopenharmony_ci ret = hfcsusb_setup_bch(bch, ch->protocol); 2228c2ecf20Sopenharmony_ci } else 2238c2ecf20Sopenharmony_ci ret = 0; 2248c2ecf20Sopenharmony_ci if (!ret) 2258c2ecf20Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 2268c2ecf20Sopenharmony_ci 0, NULL, GFP_KERNEL); 2278c2ecf20Sopenharmony_ci break; 2288c2ecf20Sopenharmony_ci case PH_DEACTIVATE_REQ: 2298c2ecf20Sopenharmony_ci deactivate_bchannel(bch); 2308c2ecf20Sopenharmony_ci _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, 2318c2ecf20Sopenharmony_ci 0, NULL, GFP_KERNEL); 2328c2ecf20Sopenharmony_ci ret = 0; 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci if (!ret) 2368c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 2378c2ecf20Sopenharmony_ci return ret; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/* 2418c2ecf20Sopenharmony_ci * send full D/B channel status information 2428c2ecf20Sopenharmony_ci * as MPH_INFORMATION_IND 2438c2ecf20Sopenharmony_ci */ 2448c2ecf20Sopenharmony_cistatic int 2458c2ecf20Sopenharmony_cihfcsusb_ph_info(struct hfcsusb *hw) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci struct ph_info *phi; 2488c2ecf20Sopenharmony_ci struct dchannel *dch = &hw->dch; 2498c2ecf20Sopenharmony_ci int i; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci phi = kzalloc(struct_size(phi, bch, dch->dev.nrbchan), GFP_ATOMIC); 2528c2ecf20Sopenharmony_ci if (!phi) 2538c2ecf20Sopenharmony_ci return -ENOMEM; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci phi->dch.ch.protocol = hw->protocol; 2568c2ecf20Sopenharmony_ci phi->dch.ch.Flags = dch->Flags; 2578c2ecf20Sopenharmony_ci phi->dch.state = dch->state; 2588c2ecf20Sopenharmony_ci phi->dch.num_bch = dch->dev.nrbchan; 2598c2ecf20Sopenharmony_ci for (i = 0; i < dch->dev.nrbchan; i++) { 2608c2ecf20Sopenharmony_ci phi->bch[i].protocol = hw->bch[i].ch.protocol; 2618c2ecf20Sopenharmony_ci phi->bch[i].Flags = hw->bch[i].Flags; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, MPH_INFORMATION_IND, MISDN_ID_ANY, 2648c2ecf20Sopenharmony_ci struct_size(phi, bch, dch->dev.nrbchan), phi, GFP_ATOMIC); 2658c2ecf20Sopenharmony_ci kfree(phi); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/* 2718c2ecf20Sopenharmony_ci * Layer2 -> Layer 1 Dchannel data 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_cistatic int 2748c2ecf20Sopenharmony_cihfcusb_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 2778c2ecf20Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 2788c2ecf20Sopenharmony_ci struct mISDNhead *hh = mISDN_HEAD_P(skb); 2798c2ecf20Sopenharmony_ci struct hfcsusb *hw = dch->hw; 2808c2ecf20Sopenharmony_ci int ret = -EINVAL; 2818c2ecf20Sopenharmony_ci u_long flags; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci switch (hh->prim) { 2848c2ecf20Sopenharmony_ci case PH_DATA_REQ: 2858c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 2868c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: PH_DATA_REQ\n", 2878c2ecf20Sopenharmony_ci hw->name, __func__); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 2908c2ecf20Sopenharmony_ci ret = dchannel_senddata(dch, skb); 2918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 2928c2ecf20Sopenharmony_ci if (ret > 0) { 2938c2ecf20Sopenharmony_ci ret = 0; 2948c2ecf20Sopenharmony_ci queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL); 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci break; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci case PH_ACTIVATE_REQ: 2998c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 3008c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: PH_ACTIVATE_REQ %s\n", 3018c2ecf20Sopenharmony_ci hw->name, __func__, 3028c2ecf20Sopenharmony_ci (hw->protocol == ISDN_P_NT_S0) ? "NT" : "TE"); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (hw->protocol == ISDN_P_NT_S0) { 3058c2ecf20Sopenharmony_ci ret = 0; 3068c2ecf20Sopenharmony_ci if (test_bit(FLG_ACTIVE, &dch->Flags)) { 3078c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, 3088c2ecf20Sopenharmony_ci PH_ACTIVATE_IND, MISDN_ID_ANY, 0, 3098c2ecf20Sopenharmony_ci NULL, GFP_ATOMIC); 3108c2ecf20Sopenharmony_ci } else { 3118c2ecf20Sopenharmony_ci hfcsusb_ph_command(hw, 3128c2ecf20Sopenharmony_ci HFC_L1_ACTIVATE_NT); 3138c2ecf20Sopenharmony_ci test_and_set_bit(FLG_L2_ACTIVATED, 3148c2ecf20Sopenharmony_ci &dch->Flags); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci } else { 3178c2ecf20Sopenharmony_ci hfcsusb_ph_command(hw, HFC_L1_ACTIVATE_TE); 3188c2ecf20Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci break; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci case PH_DEACTIVATE_REQ: 3238c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 3248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: PH_DEACTIVATE_REQ\n", 3258c2ecf20Sopenharmony_ci hw->name, __func__); 3268c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (hw->protocol == ISDN_P_NT_S0) { 3298c2ecf20Sopenharmony_ci struct sk_buff_head free_queue; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci __skb_queue_head_init(&free_queue); 3328c2ecf20Sopenharmony_ci hfcsusb_ph_command(hw, HFC_L1_DEACTIVATE_NT); 3338c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 3348c2ecf20Sopenharmony_ci skb_queue_splice_init(&dch->squeue, &free_queue); 3358c2ecf20Sopenharmony_ci if (dch->tx_skb) { 3368c2ecf20Sopenharmony_ci __skb_queue_tail(&free_queue, dch->tx_skb); 3378c2ecf20Sopenharmony_ci dch->tx_skb = NULL; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci dch->tx_idx = 0; 3408c2ecf20Sopenharmony_ci if (dch->rx_skb) { 3418c2ecf20Sopenharmony_ci __skb_queue_tail(&free_queue, dch->rx_skb); 3428c2ecf20Sopenharmony_ci dch->rx_skb = NULL; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 3458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 3468c2ecf20Sopenharmony_ci __skb_queue_purge(&free_queue); 3478c2ecf20Sopenharmony_ci#ifdef FIXME 3488c2ecf20Sopenharmony_ci if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) 3498c2ecf20Sopenharmony_ci dchannel_sched_event(&hc->dch, D_CLEARBUSY); 3508c2ecf20Sopenharmony_ci#endif 3518c2ecf20Sopenharmony_ci ret = 0; 3528c2ecf20Sopenharmony_ci } else 3538c2ecf20Sopenharmony_ci ret = l1_event(dch->l1, hh->prim); 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci case MPH_INFORMATION_REQ: 3568c2ecf20Sopenharmony_ci ret = hfcsusb_ph_info(hw); 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return ret; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci/* 3648c2ecf20Sopenharmony_ci * Layer 1 callback function 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_cistatic int 3678c2ecf20Sopenharmony_cihfc_l1callback(struct dchannel *dch, u_int cmd) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci struct hfcsusb *hw = dch->hw; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 3728c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s cmd 0x%x\n", 3738c2ecf20Sopenharmony_ci hw->name, __func__, cmd); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci switch (cmd) { 3768c2ecf20Sopenharmony_ci case INFO3_P8: 3778c2ecf20Sopenharmony_ci case INFO3_P10: 3788c2ecf20Sopenharmony_ci case HW_RESET_REQ: 3798c2ecf20Sopenharmony_ci case HW_POWERUP_REQ: 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci case HW_DEACT_REQ: 3838c2ecf20Sopenharmony_ci skb_queue_purge(&dch->squeue); 3848c2ecf20Sopenharmony_ci if (dch->tx_skb) { 3858c2ecf20Sopenharmony_ci dev_kfree_skb(dch->tx_skb); 3868c2ecf20Sopenharmony_ci dch->tx_skb = NULL; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci dch->tx_idx = 0; 3898c2ecf20Sopenharmony_ci if (dch->rx_skb) { 3908c2ecf20Sopenharmony_ci dev_kfree_skb(dch->rx_skb); 3918c2ecf20Sopenharmony_ci dch->rx_skb = NULL; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci case PH_ACTIVATE_IND: 3968c2ecf20Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 3978c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 3988c2ecf20Sopenharmony_ci GFP_ATOMIC); 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci case PH_DEACTIVATE_IND: 4018c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 4028c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, 4038c2ecf20Sopenharmony_ci GFP_ATOMIC); 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci default: 4068c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW) 4078c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: unknown cmd %x\n", 4088c2ecf20Sopenharmony_ci hw->name, __func__, cmd); 4098c2ecf20Sopenharmony_ci return -1; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci return hfcsusb_ph_info(hw); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic int 4158c2ecf20Sopenharmony_ciopen_dchannel(struct hfcsusb *hw, struct mISDNchannel *ch, 4168c2ecf20Sopenharmony_ci struct channel_req *rq) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci int err = 0; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (debug & DEBUG_HW_OPEN) 4218c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: dev(%d) open addr(%i) from %p\n", 4228c2ecf20Sopenharmony_ci hw->name, __func__, hw->dch.dev.id, rq->adr.channel, 4238c2ecf20Sopenharmony_ci __builtin_return_address(0)); 4248c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 4258c2ecf20Sopenharmony_ci return -EINVAL; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &hw->dch.Flags); 4288c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &hw->ech.Flags); 4298c2ecf20Sopenharmony_ci hfcsusb_start_endpoint(hw, HFC_CHAN_D); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* E-Channel logging */ 4328c2ecf20Sopenharmony_ci if (rq->adr.channel == 1) { 4338c2ecf20Sopenharmony_ci if (hw->fifos[HFCUSB_PCM_RX].pipe) { 4348c2ecf20Sopenharmony_ci hfcsusb_start_endpoint(hw, HFC_CHAN_E); 4358c2ecf20Sopenharmony_ci set_bit(FLG_ACTIVE, &hw->ech.Flags); 4368c2ecf20Sopenharmony_ci _queue_data(&hw->ech.dev.D, PH_ACTIVATE_IND, 4378c2ecf20Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 4388c2ecf20Sopenharmony_ci } else 4398c2ecf20Sopenharmony_ci return -EINVAL; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci if (!hw->initdone) { 4438c2ecf20Sopenharmony_ci hw->protocol = rq->protocol; 4448c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_TE_S0) { 4458c2ecf20Sopenharmony_ci err = create_l1(&hw->dch, hfc_l1callback); 4468c2ecf20Sopenharmony_ci if (err) 4478c2ecf20Sopenharmony_ci return err; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci setPortMode(hw); 4508c2ecf20Sopenharmony_ci ch->protocol = rq->protocol; 4518c2ecf20Sopenharmony_ci hw->initdone = 1; 4528c2ecf20Sopenharmony_ci } else { 4538c2ecf20Sopenharmony_ci if (rq->protocol != ch->protocol) 4548c2ecf20Sopenharmony_ci return -EPROTONOSUPPORT; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (((ch->protocol == ISDN_P_NT_S0) && (hw->dch.state == 3)) || 4588c2ecf20Sopenharmony_ci ((ch->protocol == ISDN_P_TE_S0) && (hw->dch.state == 7))) 4598c2ecf20Sopenharmony_ci _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, 4608c2ecf20Sopenharmony_ci 0, NULL, GFP_KERNEL); 4618c2ecf20Sopenharmony_ci rq->ch = ch; 4628c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 4638c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: %s: cannot get module\n", 4648c2ecf20Sopenharmony_ci hw->name, __func__); 4658c2ecf20Sopenharmony_ci return 0; 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int 4698c2ecf20Sopenharmony_ciopen_bchannel(struct hfcsusb *hw, struct channel_req *rq) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci struct bchannel *bch; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci if (rq->adr.channel == 0 || rq->adr.channel > 2) 4748c2ecf20Sopenharmony_ci return -EINVAL; 4758c2ecf20Sopenharmony_ci if (rq->protocol == ISDN_P_NONE) 4768c2ecf20Sopenharmony_ci return -EINVAL; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 4798c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s B%i\n", 4808c2ecf20Sopenharmony_ci hw->name, __func__, rq->adr.channel); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci bch = &hw->bch[rq->adr.channel - 1]; 4838c2ecf20Sopenharmony_ci if (test_and_set_bit(FLG_OPEN, &bch->Flags)) 4848c2ecf20Sopenharmony_ci return -EBUSY; /* b-channel can be only open once */ 4858c2ecf20Sopenharmony_ci bch->ch.protocol = rq->protocol; 4868c2ecf20Sopenharmony_ci rq->ch = &bch->ch; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (!try_module_get(THIS_MODULE)) 4898c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: %s:cannot get module\n", 4908c2ecf20Sopenharmony_ci hw->name, __func__); 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int 4958c2ecf20Sopenharmony_cichannel_ctrl(struct hfcsusb *hw, struct mISDN_ctrl_req *cq) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci int ret = 0; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 5008c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s op(0x%x) channel(0x%x)\n", 5018c2ecf20Sopenharmony_ci hw->name, __func__, (cq->op), (cq->channel)); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci switch (cq->op) { 5048c2ecf20Sopenharmony_ci case MISDN_CTRL_GETOP: 5058c2ecf20Sopenharmony_ci cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT | 5068c2ecf20Sopenharmony_ci MISDN_CTRL_DISCONNECT; 5078c2ecf20Sopenharmony_ci break; 5088c2ecf20Sopenharmony_ci default: 5098c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: %s: unknown Op %x\n", 5108c2ecf20Sopenharmony_ci hw->name, __func__, cq->op); 5118c2ecf20Sopenharmony_ci ret = -EINVAL; 5128c2ecf20Sopenharmony_ci break; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci return ret; 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci/* 5188c2ecf20Sopenharmony_ci * device control function 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_cistatic int 5218c2ecf20Sopenharmony_cihfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); 5248c2ecf20Sopenharmony_ci struct dchannel *dch = container_of(dev, struct dchannel, dev); 5258c2ecf20Sopenharmony_ci struct hfcsusb *hw = dch->hw; 5268c2ecf20Sopenharmony_ci struct channel_req *rq; 5278c2ecf20Sopenharmony_ci int err = 0; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW) 5308c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: cmd:%x %p\n", 5318c2ecf20Sopenharmony_ci hw->name, __func__, cmd, arg); 5328c2ecf20Sopenharmony_ci switch (cmd) { 5338c2ecf20Sopenharmony_ci case OPEN_CHANNEL: 5348c2ecf20Sopenharmony_ci rq = arg; 5358c2ecf20Sopenharmony_ci if ((rq->protocol == ISDN_P_TE_S0) || 5368c2ecf20Sopenharmony_ci (rq->protocol == ISDN_P_NT_S0)) 5378c2ecf20Sopenharmony_ci err = open_dchannel(hw, ch, rq); 5388c2ecf20Sopenharmony_ci else 5398c2ecf20Sopenharmony_ci err = open_bchannel(hw, rq); 5408c2ecf20Sopenharmony_ci if (!err) 5418c2ecf20Sopenharmony_ci hw->open++; 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 5448c2ecf20Sopenharmony_ci hw->open--; 5458c2ecf20Sopenharmony_ci if (debug & DEBUG_HW_OPEN) 5468c2ecf20Sopenharmony_ci printk(KERN_DEBUG 5478c2ecf20Sopenharmony_ci "%s: %s: dev(%d) close from %p (open %d)\n", 5488c2ecf20Sopenharmony_ci hw->name, __func__, hw->dch.dev.id, 5498c2ecf20Sopenharmony_ci __builtin_return_address(0), hw->open); 5508c2ecf20Sopenharmony_ci if (!hw->open) { 5518c2ecf20Sopenharmony_ci hfcsusb_stop_endpoint(hw, HFC_CHAN_D); 5528c2ecf20Sopenharmony_ci if (hw->fifos[HFCUSB_PCM_RX].pipe) 5538c2ecf20Sopenharmony_ci hfcsusb_stop_endpoint(hw, HFC_CHAN_E); 5548c2ecf20Sopenharmony_ci handle_led(hw, LED_POWER_ON); 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 5578c2ecf20Sopenharmony_ci break; 5588c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 5598c2ecf20Sopenharmony_ci err = channel_ctrl(hw, arg); 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci default: 5628c2ecf20Sopenharmony_ci if (dch->debug & DEBUG_HW) 5638c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: unknown command %x\n", 5648c2ecf20Sopenharmony_ci hw->name, __func__, cmd); 5658c2ecf20Sopenharmony_ci return -EINVAL; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci return err; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci/* 5718c2ecf20Sopenharmony_ci * S0 TE state change event handler 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_cistatic void 5748c2ecf20Sopenharmony_ciph_state_te(struct dchannel *dch) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci struct hfcsusb *hw = dch->hw; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) { 5798c2ecf20Sopenharmony_ci if (dch->state <= HFC_MAX_TE_LAYER1_STATE) 5808c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: %s\n", hw->name, __func__, 5818c2ecf20Sopenharmony_ci HFC_TE_LAYER1_STATES[dch->state]); 5828c2ecf20Sopenharmony_ci else 5838c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: TE F%d\n", 5848c2ecf20Sopenharmony_ci hw->name, __func__, dch->state); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci switch (dch->state) { 5888c2ecf20Sopenharmony_ci case 0: 5898c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_RESET_IND); 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci case 3: 5928c2ecf20Sopenharmony_ci l1_event(dch->l1, HW_DEACT_IND); 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci case 5: 5958c2ecf20Sopenharmony_ci case 8: 5968c2ecf20Sopenharmony_ci l1_event(dch->l1, ANYSIGNAL); 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci case 6: 5998c2ecf20Sopenharmony_ci l1_event(dch->l1, INFO2); 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci case 7: 6028c2ecf20Sopenharmony_ci l1_event(dch->l1, INFO4_P8); 6038c2ecf20Sopenharmony_ci break; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci if (dch->state == 7) 6068c2ecf20Sopenharmony_ci handle_led(hw, LED_S0_ON); 6078c2ecf20Sopenharmony_ci else 6088c2ecf20Sopenharmony_ci handle_led(hw, LED_S0_OFF); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/* 6128c2ecf20Sopenharmony_ci * S0 NT state change event handler 6138c2ecf20Sopenharmony_ci */ 6148c2ecf20Sopenharmony_cistatic void 6158c2ecf20Sopenharmony_ciph_state_nt(struct dchannel *dch) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct hfcsusb *hw = dch->hw; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) { 6208c2ecf20Sopenharmony_ci if (dch->state <= HFC_MAX_NT_LAYER1_STATE) 6218c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: %s\n", 6228c2ecf20Sopenharmony_ci hw->name, __func__, 6238c2ecf20Sopenharmony_ci HFC_NT_LAYER1_STATES[dch->state]); 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci else 6268c2ecf20Sopenharmony_ci printk(KERN_INFO DRIVER_NAME "%s: %s: NT G%d\n", 6278c2ecf20Sopenharmony_ci hw->name, __func__, dch->state); 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci switch (dch->state) { 6318c2ecf20Sopenharmony_ci case (1): 6328c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_ACTIVE, &dch->Flags); 6338c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); 6348c2ecf20Sopenharmony_ci hw->nt_timer = 0; 6358c2ecf20Sopenharmony_ci hw->timers &= ~NT_ACTIVATION_TIMER; 6368c2ecf20Sopenharmony_ci handle_led(hw, LED_S0_OFF); 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci case (2): 6408c2ecf20Sopenharmony_ci if (hw->nt_timer < 0) { 6418c2ecf20Sopenharmony_ci hw->nt_timer = 0; 6428c2ecf20Sopenharmony_ci hw->timers &= ~NT_ACTIVATION_TIMER; 6438c2ecf20Sopenharmony_ci hfcsusb_ph_command(dch->hw, HFC_L1_DEACTIVATE_NT); 6448c2ecf20Sopenharmony_ci } else { 6458c2ecf20Sopenharmony_ci hw->timers |= NT_ACTIVATION_TIMER; 6468c2ecf20Sopenharmony_ci hw->nt_timer = NT_T1_COUNT; 6478c2ecf20Sopenharmony_ci /* allow G2 -> G3 transition */ 6488c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, 2 | HFCUSB_NT_G2_G3); 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci break; 6518c2ecf20Sopenharmony_ci case (3): 6528c2ecf20Sopenharmony_ci hw->nt_timer = 0; 6538c2ecf20Sopenharmony_ci hw->timers &= ~NT_ACTIVATION_TIMER; 6548c2ecf20Sopenharmony_ci test_and_set_bit(FLG_ACTIVE, &dch->Flags); 6558c2ecf20Sopenharmony_ci _queue_data(&dch->dev.D, PH_ACTIVATE_IND, 6568c2ecf20Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 6578c2ecf20Sopenharmony_ci handle_led(hw, LED_S0_ON); 6588c2ecf20Sopenharmony_ci break; 6598c2ecf20Sopenharmony_ci case (4): 6608c2ecf20Sopenharmony_ci hw->nt_timer = 0; 6618c2ecf20Sopenharmony_ci hw->timers &= ~NT_ACTIVATION_TIMER; 6628c2ecf20Sopenharmony_ci break; 6638c2ecf20Sopenharmony_ci default: 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci hfcsusb_ph_info(hw); 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic void 6708c2ecf20Sopenharmony_ciph_state(struct dchannel *dch) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci struct hfcsusb *hw = dch->hw; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (hw->protocol == ISDN_P_NT_S0) 6758c2ecf20Sopenharmony_ci ph_state_nt(dch); 6768c2ecf20Sopenharmony_ci else if (hw->protocol == ISDN_P_TE_S0) 6778c2ecf20Sopenharmony_ci ph_state_te(dch); 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci/* 6818c2ecf20Sopenharmony_ci * disable/enable BChannel for desired protocoll 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_cistatic int 6848c2ecf20Sopenharmony_cihfcsusb_setup_bch(struct bchannel *bch, int protocol) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct hfcsusb *hw = bch->hw; 6878c2ecf20Sopenharmony_ci __u8 conhdlc, sctrl, sctrl_r; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 6908c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: protocol %x-->%x B%d\n", 6918c2ecf20Sopenharmony_ci hw->name, __func__, bch->state, protocol, 6928c2ecf20Sopenharmony_ci bch->nr); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci /* setup val for CON_HDLC */ 6958c2ecf20Sopenharmony_ci conhdlc = 0; 6968c2ecf20Sopenharmony_ci if (protocol > ISDN_P_NONE) 6978c2ecf20Sopenharmony_ci conhdlc = 8; /* enable FIFO */ 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci switch (protocol) { 7008c2ecf20Sopenharmony_ci case (-1): /* used for init */ 7018c2ecf20Sopenharmony_ci bch->state = -1; 7028c2ecf20Sopenharmony_ci fallthrough; 7038c2ecf20Sopenharmony_ci case (ISDN_P_NONE): 7048c2ecf20Sopenharmony_ci if (bch->state == ISDN_P_NONE) 7058c2ecf20Sopenharmony_ci return 0; /* already in idle state */ 7068c2ecf20Sopenharmony_ci bch->state = ISDN_P_NONE; 7078c2ecf20Sopenharmony_ci clear_bit(FLG_HDLC, &bch->Flags); 7088c2ecf20Sopenharmony_ci clear_bit(FLG_TRANSPARENT, &bch->Flags); 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci case (ISDN_P_B_RAW): 7118c2ecf20Sopenharmony_ci conhdlc |= 2; 7128c2ecf20Sopenharmony_ci bch->state = protocol; 7138c2ecf20Sopenharmony_ci set_bit(FLG_TRANSPARENT, &bch->Flags); 7148c2ecf20Sopenharmony_ci break; 7158c2ecf20Sopenharmony_ci case (ISDN_P_B_HDLC): 7168c2ecf20Sopenharmony_ci bch->state = protocol; 7178c2ecf20Sopenharmony_ci set_bit(FLG_HDLC, &bch->Flags); 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci default: 7208c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 7218c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: prot not known %x\n", 7228c2ecf20Sopenharmony_ci hw->name, __func__, protocol); 7238c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (protocol >= ISDN_P_NONE) { 7278c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_FIFO, (bch->nr == 1) ? 0 : 2); 7288c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_CON_HDLC, conhdlc); 7298c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_INC_RES_F, 2); 7308c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_FIFO, (bch->nr == 1) ? 1 : 3); 7318c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_CON_HDLC, conhdlc); 7328c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_INC_RES_F, 2); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci sctrl = 0x40 + ((hw->protocol == ISDN_P_TE_S0) ? 0x00 : 0x04); 7358c2ecf20Sopenharmony_ci sctrl_r = 0x0; 7368c2ecf20Sopenharmony_ci if (test_bit(FLG_ACTIVE, &hw->bch[0].Flags)) { 7378c2ecf20Sopenharmony_ci sctrl |= 1; 7388c2ecf20Sopenharmony_ci sctrl_r |= 1; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci if (test_bit(FLG_ACTIVE, &hw->bch[1].Flags)) { 7418c2ecf20Sopenharmony_ci sctrl |= 2; 7428c2ecf20Sopenharmony_ci sctrl_r |= 2; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_SCTRL, sctrl); 7458c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_SCTRL_R, sctrl_r); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (protocol > ISDN_P_NONE) 7488c2ecf20Sopenharmony_ci handle_led(hw, (bch->nr == 1) ? LED_B1_ON : LED_B2_ON); 7498c2ecf20Sopenharmony_ci else 7508c2ecf20Sopenharmony_ci handle_led(hw, (bch->nr == 1) ? LED_B1_OFF : 7518c2ecf20Sopenharmony_ci LED_B2_OFF); 7528c2ecf20Sopenharmony_ci } 7538c2ecf20Sopenharmony_ci return hfcsusb_ph_info(hw); 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic void 7578c2ecf20Sopenharmony_cihfcsusb_ph_command(struct hfcsusb *hw, u_char command) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 7608c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: %x\n", 7618c2ecf20Sopenharmony_ci hw->name, __func__, command); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci switch (command) { 7648c2ecf20Sopenharmony_ci case HFC_L1_ACTIVATE_TE: 7658c2ecf20Sopenharmony_ci /* force sending sending INFO1 */ 7668c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, 0x14); 7678c2ecf20Sopenharmony_ci /* start l1 activation */ 7688c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, 0x04); 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci case HFC_L1_FORCE_DEACTIVATE_TE: 7728c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, 0x10); 7738c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, 0x03); 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci case HFC_L1_ACTIVATE_NT: 7778c2ecf20Sopenharmony_ci if (hw->dch.state == 3) 7788c2ecf20Sopenharmony_ci _queue_data(&hw->dch.dev.D, PH_ACTIVATE_IND, 7798c2ecf20Sopenharmony_ci MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); 7808c2ecf20Sopenharmony_ci else 7818c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, HFCUSB_ACTIVATE | 7828c2ecf20Sopenharmony_ci HFCUSB_DO_ACTION | HFCUSB_NT_G2_G3); 7838c2ecf20Sopenharmony_ci break; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci case HFC_L1_DEACTIVATE_NT: 7868c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, 7878c2ecf20Sopenharmony_ci HFCUSB_DO_ACTION); 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci/* 7938c2ecf20Sopenharmony_ci * Layer 1 B-channel hardware access 7948c2ecf20Sopenharmony_ci */ 7958c2ecf20Sopenharmony_cistatic int 7968c2ecf20Sopenharmony_cichannel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci return mISDN_ctrl_bchannel(bch, cq); 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci/* collect data from incoming interrupt or isochron USB data */ 8028c2ecf20Sopenharmony_cistatic void 8038c2ecf20Sopenharmony_cihfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, 8048c2ecf20Sopenharmony_ci int finish) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci struct hfcsusb *hw = fifo->hw; 8078c2ecf20Sopenharmony_ci struct sk_buff *rx_skb = NULL; 8088c2ecf20Sopenharmony_ci int maxlen = 0; 8098c2ecf20Sopenharmony_ci int fifon = fifo->fifonum; 8108c2ecf20Sopenharmony_ci int i; 8118c2ecf20Sopenharmony_ci int hdlc = 0; 8128c2ecf20Sopenharmony_ci unsigned long flags; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 8158c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: fifo(%i) len(%i) " 8168c2ecf20Sopenharmony_ci "dch(%p) bch(%p) ech(%p)\n", 8178c2ecf20Sopenharmony_ci hw->name, __func__, fifon, len, 8188c2ecf20Sopenharmony_ci fifo->dch, fifo->bch, fifo->ech); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (!len) 8218c2ecf20Sopenharmony_ci return; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci if ((!!fifo->dch + !!fifo->bch + !!fifo->ech) != 1) { 8248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: undefined channel\n", 8258c2ecf20Sopenharmony_ci hw->name, __func__); 8268c2ecf20Sopenharmony_ci return; 8278c2ecf20Sopenharmony_ci } 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 8308c2ecf20Sopenharmony_ci if (fifo->dch) { 8318c2ecf20Sopenharmony_ci rx_skb = fifo->dch->rx_skb; 8328c2ecf20Sopenharmony_ci maxlen = fifo->dch->maxlen; 8338c2ecf20Sopenharmony_ci hdlc = 1; 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci if (fifo->bch) { 8368c2ecf20Sopenharmony_ci if (test_bit(FLG_RX_OFF, &fifo->bch->Flags)) { 8378c2ecf20Sopenharmony_ci fifo->bch->dropcnt += len; 8388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 8398c2ecf20Sopenharmony_ci return; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci maxlen = bchannel_get_rxbuf(fifo->bch, len); 8428c2ecf20Sopenharmony_ci rx_skb = fifo->bch->rx_skb; 8438c2ecf20Sopenharmony_ci if (maxlen < 0) { 8448c2ecf20Sopenharmony_ci if (rx_skb) 8458c2ecf20Sopenharmony_ci skb_trim(rx_skb, 0); 8468c2ecf20Sopenharmony_ci pr_warn("%s.B%d: No bufferspace for %d bytes\n", 8478c2ecf20Sopenharmony_ci hw->name, fifo->bch->nr, len); 8488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 8498c2ecf20Sopenharmony_ci return; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci maxlen = fifo->bch->maxlen; 8528c2ecf20Sopenharmony_ci hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); 8538c2ecf20Sopenharmony_ci } 8548c2ecf20Sopenharmony_ci if (fifo->ech) { 8558c2ecf20Sopenharmony_ci rx_skb = fifo->ech->rx_skb; 8568c2ecf20Sopenharmony_ci maxlen = fifo->ech->maxlen; 8578c2ecf20Sopenharmony_ci hdlc = 1; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (fifo->dch || fifo->ech) { 8618c2ecf20Sopenharmony_ci if (!rx_skb) { 8628c2ecf20Sopenharmony_ci rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC); 8638c2ecf20Sopenharmony_ci if (rx_skb) { 8648c2ecf20Sopenharmony_ci if (fifo->dch) 8658c2ecf20Sopenharmony_ci fifo->dch->rx_skb = rx_skb; 8668c2ecf20Sopenharmony_ci if (fifo->ech) 8678c2ecf20Sopenharmony_ci fifo->ech->rx_skb = rx_skb; 8688c2ecf20Sopenharmony_ci skb_trim(rx_skb, 0); 8698c2ecf20Sopenharmony_ci } else { 8708c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n", 8718c2ecf20Sopenharmony_ci hw->name, __func__); 8728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 8738c2ecf20Sopenharmony_ci return; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci /* D/E-Channel SKB range check */ 8778c2ecf20Sopenharmony_ci if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) { 8788c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: sbk mem exceeded " 8798c2ecf20Sopenharmony_ci "for fifo(%d) HFCUSB_D_RX\n", 8808c2ecf20Sopenharmony_ci hw->name, __func__, fifon); 8818c2ecf20Sopenharmony_ci skb_trim(rx_skb, 0); 8828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 8838c2ecf20Sopenharmony_ci return; 8848c2ecf20Sopenharmony_ci } 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci skb_put_data(rx_skb, data, len); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (hdlc) { 8908c2ecf20Sopenharmony_ci /* we have a complete hdlc packet */ 8918c2ecf20Sopenharmony_ci if (finish) { 8928c2ecf20Sopenharmony_ci if ((rx_skb->len > 3) && 8938c2ecf20Sopenharmony_ci (!(rx_skb->data[rx_skb->len - 1]))) { 8948c2ecf20Sopenharmony_ci if (debug & DBG_HFC_FIFO_VERBOSE) { 8958c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: fifon(%i)" 8968c2ecf20Sopenharmony_ci " new RX len(%i): ", 8978c2ecf20Sopenharmony_ci hw->name, __func__, fifon, 8988c2ecf20Sopenharmony_ci rx_skb->len); 8998c2ecf20Sopenharmony_ci i = 0; 9008c2ecf20Sopenharmony_ci while (i < rx_skb->len) 9018c2ecf20Sopenharmony_ci printk("%02x ", 9028c2ecf20Sopenharmony_ci rx_skb->data[i++]); 9038c2ecf20Sopenharmony_ci printk("\n"); 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci /* remove CRC & status */ 9078c2ecf20Sopenharmony_ci skb_trim(rx_skb, rx_skb->len - 3); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if (fifo->dch) 9108c2ecf20Sopenharmony_ci recv_Dchannel(fifo->dch); 9118c2ecf20Sopenharmony_ci if (fifo->bch) 9128c2ecf20Sopenharmony_ci recv_Bchannel(fifo->bch, MISDN_ID_ANY, 9138c2ecf20Sopenharmony_ci 0); 9148c2ecf20Sopenharmony_ci if (fifo->ech) 9158c2ecf20Sopenharmony_ci recv_Echannel(fifo->ech, 9168c2ecf20Sopenharmony_ci &hw->dch); 9178c2ecf20Sopenharmony_ci } else { 9188c2ecf20Sopenharmony_ci if (debug & DBG_HFC_FIFO_VERBOSE) { 9198c2ecf20Sopenharmony_ci printk(KERN_DEBUG 9208c2ecf20Sopenharmony_ci "%s: CRC or minlen ERROR fifon(%i) " 9218c2ecf20Sopenharmony_ci "RX len(%i): ", 9228c2ecf20Sopenharmony_ci hw->name, fifon, rx_skb->len); 9238c2ecf20Sopenharmony_ci i = 0; 9248c2ecf20Sopenharmony_ci while (i < rx_skb->len) 9258c2ecf20Sopenharmony_ci printk("%02x ", 9268c2ecf20Sopenharmony_ci rx_skb->data[i++]); 9278c2ecf20Sopenharmony_ci printk("\n"); 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci skb_trim(rx_skb, 0); 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci } else { 9338c2ecf20Sopenharmony_ci /* deliver transparent data to layer2 */ 9348c2ecf20Sopenharmony_ci recv_Bchannel(fifo->bch, MISDN_ID_ANY, false); 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic void 9408c2ecf20Sopenharmony_cifill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, 9418c2ecf20Sopenharmony_ci void *buf, int num_packets, int packet_size, int interval, 9428c2ecf20Sopenharmony_ci usb_complete_t complete, void *context) 9438c2ecf20Sopenharmony_ci{ 9448c2ecf20Sopenharmony_ci int k; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci usb_fill_bulk_urb(urb, dev, pipe, buf, packet_size * num_packets, 9478c2ecf20Sopenharmony_ci complete, context); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci urb->number_of_packets = num_packets; 9508c2ecf20Sopenharmony_ci urb->transfer_flags = URB_ISO_ASAP; 9518c2ecf20Sopenharmony_ci urb->actual_length = 0; 9528c2ecf20Sopenharmony_ci urb->interval = interval; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci for (k = 0; k < num_packets; k++) { 9558c2ecf20Sopenharmony_ci urb->iso_frame_desc[k].offset = packet_size * k; 9568c2ecf20Sopenharmony_ci urb->iso_frame_desc[k].length = packet_size; 9578c2ecf20Sopenharmony_ci urb->iso_frame_desc[k].actual_length = 0; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci} 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci/* receive completion routine for all ISO tx fifos */ 9628c2ecf20Sopenharmony_cistatic void 9638c2ecf20Sopenharmony_cirx_iso_complete(struct urb *urb) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context; 9668c2ecf20Sopenharmony_ci struct usb_fifo *fifo = context_iso_urb->owner_fifo; 9678c2ecf20Sopenharmony_ci struct hfcsusb *hw = fifo->hw; 9688c2ecf20Sopenharmony_ci int k, len, errcode, offset, num_isoc_packets, fifon, maxlen, 9698c2ecf20Sopenharmony_ci status, iso_status, i; 9708c2ecf20Sopenharmony_ci __u8 *buf; 9718c2ecf20Sopenharmony_ci static __u8 eof[8]; 9728c2ecf20Sopenharmony_ci __u8 s0_state; 9738c2ecf20Sopenharmony_ci unsigned long flags; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci fifon = fifo->fifonum; 9768c2ecf20Sopenharmony_ci status = urb->status; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 9798c2ecf20Sopenharmony_ci if (fifo->stop_gracefull) { 9808c2ecf20Sopenharmony_ci fifo->stop_gracefull = 0; 9818c2ecf20Sopenharmony_ci fifo->active = 0; 9828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 9838c2ecf20Sopenharmony_ci return; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* 9888c2ecf20Sopenharmony_ci * ISO transfer only partially completed, 9898c2ecf20Sopenharmony_ci * look at individual frame status for details 9908c2ecf20Sopenharmony_ci */ 9918c2ecf20Sopenharmony_ci if (status == -EXDEV) { 9928c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 9938c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: with -EXDEV " 9948c2ecf20Sopenharmony_ci "urb->status %d, fifonum %d\n", 9958c2ecf20Sopenharmony_ci hw->name, __func__, status, fifon); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* clear status, so go on with ISO transfers */ 9988c2ecf20Sopenharmony_ci status = 0; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci s0_state = 0; 10028c2ecf20Sopenharmony_ci if (fifo->active && !status) { 10038c2ecf20Sopenharmony_ci num_isoc_packets = iso_packets[fifon]; 10048c2ecf20Sopenharmony_ci maxlen = fifo->usb_packet_maxlen; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci for (k = 0; k < num_isoc_packets; ++k) { 10078c2ecf20Sopenharmony_ci len = urb->iso_frame_desc[k].actual_length; 10088c2ecf20Sopenharmony_ci offset = urb->iso_frame_desc[k].offset; 10098c2ecf20Sopenharmony_ci buf = context_iso_urb->buffer + offset; 10108c2ecf20Sopenharmony_ci iso_status = urb->iso_frame_desc[k].status; 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (iso_status && (debug & DBG_HFC_FIFO_VERBOSE)) { 10138c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: " 10148c2ecf20Sopenharmony_ci "ISO packet %i, status: %i\n", 10158c2ecf20Sopenharmony_ci hw->name, __func__, k, iso_status); 10168c2ecf20Sopenharmony_ci } 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci /* USB data log for every D ISO in */ 10198c2ecf20Sopenharmony_ci if ((fifon == HFCUSB_D_RX) && 10208c2ecf20Sopenharmony_ci (debug & DBG_HFC_USB_VERBOSE)) { 10218c2ecf20Sopenharmony_ci printk(KERN_DEBUG 10228c2ecf20Sopenharmony_ci "%s: %s: %d (%d/%d) len(%d) ", 10238c2ecf20Sopenharmony_ci hw->name, __func__, urb->start_frame, 10248c2ecf20Sopenharmony_ci k, num_isoc_packets - 1, 10258c2ecf20Sopenharmony_ci len); 10268c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 10278c2ecf20Sopenharmony_ci printk("%x ", buf[i]); 10288c2ecf20Sopenharmony_ci printk("\n"); 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (!iso_status) { 10328c2ecf20Sopenharmony_ci if (fifo->last_urblen != maxlen) { 10338c2ecf20Sopenharmony_ci /* 10348c2ecf20Sopenharmony_ci * save fifo fill-level threshold bits 10358c2ecf20Sopenharmony_ci * to use them later in TX ISO URB 10368c2ecf20Sopenharmony_ci * completions 10378c2ecf20Sopenharmony_ci */ 10388c2ecf20Sopenharmony_ci hw->threshold_mask = buf[1]; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (fifon == HFCUSB_D_RX) 10418c2ecf20Sopenharmony_ci s0_state = (buf[0] >> 4); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci eof[fifon] = buf[0] & 1; 10448c2ecf20Sopenharmony_ci if (len > 2) 10458c2ecf20Sopenharmony_ci hfcsusb_rx_frame(fifo, buf + 2, 10468c2ecf20Sopenharmony_ci len - 2, (len < maxlen) 10478c2ecf20Sopenharmony_ci ? eof[fifon] : 0); 10488c2ecf20Sopenharmony_ci } else 10498c2ecf20Sopenharmony_ci hfcsusb_rx_frame(fifo, buf, len, 10508c2ecf20Sopenharmony_ci (len < maxlen) ? 10518c2ecf20Sopenharmony_ci eof[fifon] : 0); 10528c2ecf20Sopenharmony_ci fifo->last_urblen = len; 10538c2ecf20Sopenharmony_ci } 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci /* signal S0 layer1 state change */ 10578c2ecf20Sopenharmony_ci if ((s0_state) && (hw->initdone) && 10588c2ecf20Sopenharmony_ci (s0_state != hw->dch.state)) { 10598c2ecf20Sopenharmony_ci hw->dch.state = s0_state; 10608c2ecf20Sopenharmony_ci schedule_event(&hw->dch, FLG_PHCHANGE); 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci fill_isoc_urb(urb, fifo->hw->dev, fifo->pipe, 10648c2ecf20Sopenharmony_ci context_iso_urb->buffer, num_isoc_packets, 10658c2ecf20Sopenharmony_ci fifo->usb_packet_maxlen, fifo->intervall, 10668c2ecf20Sopenharmony_ci (usb_complete_t)rx_iso_complete, urb->context); 10678c2ecf20Sopenharmony_ci errcode = usb_submit_urb(urb, GFP_ATOMIC); 10688c2ecf20Sopenharmony_ci if (errcode < 0) { 10698c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 10708c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: error submitting " 10718c2ecf20Sopenharmony_ci "ISO URB: %d\n", 10728c2ecf20Sopenharmony_ci hw->name, __func__, errcode); 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci } else { 10758c2ecf20Sopenharmony_ci if (status && (debug & DBG_HFC_URB_INFO)) 10768c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: rx_iso_complete : " 10778c2ecf20Sopenharmony_ci "urb->status %d, fifonum %d\n", 10788c2ecf20Sopenharmony_ci hw->name, __func__, status, fifon); 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci} 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci/* receive completion routine for all interrupt rx fifos */ 10838c2ecf20Sopenharmony_cistatic void 10848c2ecf20Sopenharmony_cirx_int_complete(struct urb *urb) 10858c2ecf20Sopenharmony_ci{ 10868c2ecf20Sopenharmony_ci int len, status, i; 10878c2ecf20Sopenharmony_ci __u8 *buf, maxlen, fifon; 10888c2ecf20Sopenharmony_ci struct usb_fifo *fifo = (struct usb_fifo *) urb->context; 10898c2ecf20Sopenharmony_ci struct hfcsusb *hw = fifo->hw; 10908c2ecf20Sopenharmony_ci static __u8 eof[8]; 10918c2ecf20Sopenharmony_ci unsigned long flags; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 10948c2ecf20Sopenharmony_ci if (fifo->stop_gracefull) { 10958c2ecf20Sopenharmony_ci fifo->stop_gracefull = 0; 10968c2ecf20Sopenharmony_ci fifo->active = 0; 10978c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 10988c2ecf20Sopenharmony_ci return; 10998c2ecf20Sopenharmony_ci } 11008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci fifon = fifo->fifonum; 11038c2ecf20Sopenharmony_ci if ((!fifo->active) || (urb->status)) { 11048c2ecf20Sopenharmony_ci if (debug & DBG_HFC_URB_ERROR) 11058c2ecf20Sopenharmony_ci printk(KERN_DEBUG 11068c2ecf20Sopenharmony_ci "%s: %s: RX-Fifo %i is going down (%i)\n", 11078c2ecf20Sopenharmony_ci hw->name, __func__, fifon, urb->status); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci fifo->urb->interval = 0; /* cancel automatic rescheduling */ 11108c2ecf20Sopenharmony_ci return; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci len = urb->actual_length; 11138c2ecf20Sopenharmony_ci buf = fifo->buffer; 11148c2ecf20Sopenharmony_ci maxlen = fifo->usb_packet_maxlen; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* USB data log for every D INT in */ 11178c2ecf20Sopenharmony_ci if ((fifon == HFCUSB_D_RX) && (debug & DBG_HFC_USB_VERBOSE)) { 11188c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: D RX INT len(%d) ", 11198c2ecf20Sopenharmony_ci hw->name, __func__, len); 11208c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 11218c2ecf20Sopenharmony_ci printk("%02x ", buf[i]); 11228c2ecf20Sopenharmony_ci printk("\n"); 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (fifo->last_urblen != fifo->usb_packet_maxlen) { 11268c2ecf20Sopenharmony_ci /* the threshold mask is in the 2nd status byte */ 11278c2ecf20Sopenharmony_ci hw->threshold_mask = buf[1]; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci /* signal S0 layer1 state change */ 11308c2ecf20Sopenharmony_ci if (hw->initdone && ((buf[0] >> 4) != hw->dch.state)) { 11318c2ecf20Sopenharmony_ci hw->dch.state = (buf[0] >> 4); 11328c2ecf20Sopenharmony_ci schedule_event(&hw->dch, FLG_PHCHANGE); 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci eof[fifon] = buf[0] & 1; 11368c2ecf20Sopenharmony_ci /* if we have more than the 2 status bytes -> collect data */ 11378c2ecf20Sopenharmony_ci if (len > 2) 11388c2ecf20Sopenharmony_ci hfcsusb_rx_frame(fifo, buf + 2, 11398c2ecf20Sopenharmony_ci urb->actual_length - 2, 11408c2ecf20Sopenharmony_ci (len < maxlen) ? eof[fifon] : 0); 11418c2ecf20Sopenharmony_ci } else { 11428c2ecf20Sopenharmony_ci hfcsusb_rx_frame(fifo, buf, urb->actual_length, 11438c2ecf20Sopenharmony_ci (len < maxlen) ? eof[fifon] : 0); 11448c2ecf20Sopenharmony_ci } 11458c2ecf20Sopenharmony_ci fifo->last_urblen = urb->actual_length; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci status = usb_submit_urb(urb, GFP_ATOMIC); 11488c2ecf20Sopenharmony_ci if (status) { 11498c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 11508c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: error resubmitting USB\n", 11518c2ecf20Sopenharmony_ci hw->name, __func__); 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci/* transmit completion routine for all ISO tx fifos */ 11568c2ecf20Sopenharmony_cistatic void 11578c2ecf20Sopenharmony_citx_iso_complete(struct urb *urb) 11588c2ecf20Sopenharmony_ci{ 11598c2ecf20Sopenharmony_ci struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context; 11608c2ecf20Sopenharmony_ci struct usb_fifo *fifo = context_iso_urb->owner_fifo; 11618c2ecf20Sopenharmony_ci struct hfcsusb *hw = fifo->hw; 11628c2ecf20Sopenharmony_ci struct sk_buff *tx_skb; 11638c2ecf20Sopenharmony_ci int k, tx_offset, num_isoc_packets, sink, remain, current_len, 11648c2ecf20Sopenharmony_ci errcode, hdlc, i; 11658c2ecf20Sopenharmony_ci int *tx_idx; 11668c2ecf20Sopenharmony_ci int frame_complete, fifon, status, fillempty = 0; 11678c2ecf20Sopenharmony_ci __u8 threshbit, *p; 11688c2ecf20Sopenharmony_ci unsigned long flags; 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 11718c2ecf20Sopenharmony_ci if (fifo->stop_gracefull) { 11728c2ecf20Sopenharmony_ci fifo->stop_gracefull = 0; 11738c2ecf20Sopenharmony_ci fifo->active = 0; 11748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 11758c2ecf20Sopenharmony_ci return; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (fifo->dch) { 11798c2ecf20Sopenharmony_ci tx_skb = fifo->dch->tx_skb; 11808c2ecf20Sopenharmony_ci tx_idx = &fifo->dch->tx_idx; 11818c2ecf20Sopenharmony_ci hdlc = 1; 11828c2ecf20Sopenharmony_ci } else if (fifo->bch) { 11838c2ecf20Sopenharmony_ci tx_skb = fifo->bch->tx_skb; 11848c2ecf20Sopenharmony_ci tx_idx = &fifo->bch->tx_idx; 11858c2ecf20Sopenharmony_ci hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); 11868c2ecf20Sopenharmony_ci if (!tx_skb && !hdlc && 11878c2ecf20Sopenharmony_ci test_bit(FLG_FILLEMPTY, &fifo->bch->Flags)) 11888c2ecf20Sopenharmony_ci fillempty = 1; 11898c2ecf20Sopenharmony_ci } else { 11908c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n", 11918c2ecf20Sopenharmony_ci hw->name, __func__); 11928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 11938c2ecf20Sopenharmony_ci return; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci fifon = fifo->fifonum; 11978c2ecf20Sopenharmony_ci status = urb->status; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci tx_offset = 0; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci /* 12028c2ecf20Sopenharmony_ci * ISO transfer only partially completed, 12038c2ecf20Sopenharmony_ci * look at individual frame status for details 12048c2ecf20Sopenharmony_ci */ 12058c2ecf20Sopenharmony_ci if (status == -EXDEV) { 12068c2ecf20Sopenharmony_ci if (debug & DBG_HFC_URB_ERROR) 12078c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: " 12088c2ecf20Sopenharmony_ci "-EXDEV (%i) fifon (%d)\n", 12098c2ecf20Sopenharmony_ci hw->name, __func__, status, fifon); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci /* clear status, so go on with ISO transfers */ 12128c2ecf20Sopenharmony_ci status = 0; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (fifo->active && !status) { 12168c2ecf20Sopenharmony_ci /* is FifoFull-threshold set for our channel? */ 12178c2ecf20Sopenharmony_ci threshbit = (hw->threshold_mask & (1 << fifon)); 12188c2ecf20Sopenharmony_ci num_isoc_packets = iso_packets[fifon]; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci /* predict dataflow to avoid fifo overflow */ 12218c2ecf20Sopenharmony_ci if (fifon >= HFCUSB_D_TX) 12228c2ecf20Sopenharmony_ci sink = (threshbit) ? SINK_DMIN : SINK_DMAX; 12238c2ecf20Sopenharmony_ci else 12248c2ecf20Sopenharmony_ci sink = (threshbit) ? SINK_MIN : SINK_MAX; 12258c2ecf20Sopenharmony_ci fill_isoc_urb(urb, fifo->hw->dev, fifo->pipe, 12268c2ecf20Sopenharmony_ci context_iso_urb->buffer, num_isoc_packets, 12278c2ecf20Sopenharmony_ci fifo->usb_packet_maxlen, fifo->intervall, 12288c2ecf20Sopenharmony_ci (usb_complete_t)tx_iso_complete, urb->context); 12298c2ecf20Sopenharmony_ci memset(context_iso_urb->buffer, 0, 12308c2ecf20Sopenharmony_ci sizeof(context_iso_urb->buffer)); 12318c2ecf20Sopenharmony_ci frame_complete = 0; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci for (k = 0; k < num_isoc_packets; ++k) { 12348c2ecf20Sopenharmony_ci /* analyze tx success of previous ISO packets */ 12358c2ecf20Sopenharmony_ci if (debug & DBG_HFC_URB_ERROR) { 12368c2ecf20Sopenharmony_ci errcode = urb->iso_frame_desc[k].status; 12378c2ecf20Sopenharmony_ci if (errcode) { 12388c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: " 12398c2ecf20Sopenharmony_ci "ISO packet %i, status: %i\n", 12408c2ecf20Sopenharmony_ci hw->name, __func__, k, errcode); 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci /* Generate next ISO Packets */ 12458c2ecf20Sopenharmony_ci if (tx_skb) 12468c2ecf20Sopenharmony_ci remain = tx_skb->len - *tx_idx; 12478c2ecf20Sopenharmony_ci else if (fillempty) 12488c2ecf20Sopenharmony_ci remain = 15; /* > not complete */ 12498c2ecf20Sopenharmony_ci else 12508c2ecf20Sopenharmony_ci remain = 0; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (remain > 0) { 12538c2ecf20Sopenharmony_ci fifo->bit_line -= sink; 12548c2ecf20Sopenharmony_ci current_len = (0 - fifo->bit_line) / 8; 12558c2ecf20Sopenharmony_ci if (current_len > 14) 12568c2ecf20Sopenharmony_ci current_len = 14; 12578c2ecf20Sopenharmony_ci if (current_len < 0) 12588c2ecf20Sopenharmony_ci current_len = 0; 12598c2ecf20Sopenharmony_ci if (remain < current_len) 12608c2ecf20Sopenharmony_ci current_len = remain; 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci /* how much bit do we put on the line? */ 12638c2ecf20Sopenharmony_ci fifo->bit_line += current_len * 8; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci context_iso_urb->buffer[tx_offset] = 0; 12668c2ecf20Sopenharmony_ci if (current_len == remain) { 12678c2ecf20Sopenharmony_ci if (hdlc) { 12688c2ecf20Sopenharmony_ci /* signal frame completion */ 12698c2ecf20Sopenharmony_ci context_iso_urb-> 12708c2ecf20Sopenharmony_ci buffer[tx_offset] = 1; 12718c2ecf20Sopenharmony_ci /* add 2 byte flags and 16bit 12728c2ecf20Sopenharmony_ci * CRC at end of ISDN frame */ 12738c2ecf20Sopenharmony_ci fifo->bit_line += 32; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci frame_complete = 1; 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci /* copy tx data to iso-urb buffer */ 12798c2ecf20Sopenharmony_ci p = context_iso_urb->buffer + tx_offset + 1; 12808c2ecf20Sopenharmony_ci if (fillempty) { 12818c2ecf20Sopenharmony_ci memset(p, fifo->bch->fill[0], 12828c2ecf20Sopenharmony_ci current_len); 12838c2ecf20Sopenharmony_ci } else { 12848c2ecf20Sopenharmony_ci memcpy(p, (tx_skb->data + *tx_idx), 12858c2ecf20Sopenharmony_ci current_len); 12868c2ecf20Sopenharmony_ci *tx_idx += current_len; 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci urb->iso_frame_desc[k].offset = tx_offset; 12898c2ecf20Sopenharmony_ci urb->iso_frame_desc[k].length = current_len + 1; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci /* USB data log for every D ISO out */ 12928c2ecf20Sopenharmony_ci if ((fifon == HFCUSB_D_RX) && !fillempty && 12938c2ecf20Sopenharmony_ci (debug & DBG_HFC_USB_VERBOSE)) { 12948c2ecf20Sopenharmony_ci printk(KERN_DEBUG 12958c2ecf20Sopenharmony_ci "%s: %s (%d/%d) offs(%d) len(%d) ", 12968c2ecf20Sopenharmony_ci hw->name, __func__, 12978c2ecf20Sopenharmony_ci k, num_isoc_packets - 1, 12988c2ecf20Sopenharmony_ci urb->iso_frame_desc[k].offset, 12998c2ecf20Sopenharmony_ci urb->iso_frame_desc[k].length); 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci for (i = urb->iso_frame_desc[k].offset; 13028c2ecf20Sopenharmony_ci i < (urb->iso_frame_desc[k].offset 13038c2ecf20Sopenharmony_ci + urb->iso_frame_desc[k].length); 13048c2ecf20Sopenharmony_ci i++) 13058c2ecf20Sopenharmony_ci printk("%x ", 13068c2ecf20Sopenharmony_ci context_iso_urb->buffer[i]); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci printk(" skb->len(%i) tx-idx(%d)\n", 13098c2ecf20Sopenharmony_ci tx_skb->len, *tx_idx); 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci tx_offset += (current_len + 1); 13138c2ecf20Sopenharmony_ci } else { 13148c2ecf20Sopenharmony_ci urb->iso_frame_desc[k].offset = tx_offset++; 13158c2ecf20Sopenharmony_ci urb->iso_frame_desc[k].length = 1; 13168c2ecf20Sopenharmony_ci /* we lower data margin every msec */ 13178c2ecf20Sopenharmony_ci fifo->bit_line -= sink; 13188c2ecf20Sopenharmony_ci if (fifo->bit_line < BITLINE_INF) 13198c2ecf20Sopenharmony_ci fifo->bit_line = BITLINE_INF; 13208c2ecf20Sopenharmony_ci } 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (frame_complete) { 13238c2ecf20Sopenharmony_ci frame_complete = 0; 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci if (debug & DBG_HFC_FIFO_VERBOSE) { 13268c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: " 13278c2ecf20Sopenharmony_ci "fifon(%i) new TX len(%i): ", 13288c2ecf20Sopenharmony_ci hw->name, __func__, 13298c2ecf20Sopenharmony_ci fifon, tx_skb->len); 13308c2ecf20Sopenharmony_ci i = 0; 13318c2ecf20Sopenharmony_ci while (i < tx_skb->len) 13328c2ecf20Sopenharmony_ci printk("%02x ", 13338c2ecf20Sopenharmony_ci tx_skb->data[i++]); 13348c2ecf20Sopenharmony_ci printk("\n"); 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci dev_consume_skb_irq(tx_skb); 13388c2ecf20Sopenharmony_ci tx_skb = NULL; 13398c2ecf20Sopenharmony_ci if (fifo->dch && get_next_dframe(fifo->dch)) 13408c2ecf20Sopenharmony_ci tx_skb = fifo->dch->tx_skb; 13418c2ecf20Sopenharmony_ci else if (fifo->bch && 13428c2ecf20Sopenharmony_ci get_next_bframe(fifo->bch)) 13438c2ecf20Sopenharmony_ci tx_skb = fifo->bch->tx_skb; 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci } 13468c2ecf20Sopenharmony_ci errcode = usb_submit_urb(urb, GFP_ATOMIC); 13478c2ecf20Sopenharmony_ci if (errcode < 0) { 13488c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 13498c2ecf20Sopenharmony_ci printk(KERN_DEBUG 13508c2ecf20Sopenharmony_ci "%s: %s: error submitting ISO URB: %d \n", 13518c2ecf20Sopenharmony_ci hw->name, __func__, errcode); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci /* 13558c2ecf20Sopenharmony_ci * abuse DChannel tx iso completion to trigger NT mode state 13568c2ecf20Sopenharmony_ci * changes tx_iso_complete is assumed to be called every 13578c2ecf20Sopenharmony_ci * fifo->intervall (ms) 13588c2ecf20Sopenharmony_ci */ 13598c2ecf20Sopenharmony_ci if ((fifon == HFCUSB_D_TX) && (hw->protocol == ISDN_P_NT_S0) 13608c2ecf20Sopenharmony_ci && (hw->timers & NT_ACTIVATION_TIMER)) { 13618c2ecf20Sopenharmony_ci if ((--hw->nt_timer) < 0) 13628c2ecf20Sopenharmony_ci schedule_event(&hw->dch, FLG_PHCHANGE); 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci } else { 13668c2ecf20Sopenharmony_ci if (status && (debug & DBG_HFC_URB_ERROR)) 13678c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: urb->status %s (%i)" 13688c2ecf20Sopenharmony_ci "fifonum=%d\n", 13698c2ecf20Sopenharmony_ci hw->name, __func__, 13708c2ecf20Sopenharmony_ci symbolic(urb_errlist, status), status, fifon); 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 13738c2ecf20Sopenharmony_ci} 13748c2ecf20Sopenharmony_ci 13758c2ecf20Sopenharmony_ci/* 13768c2ecf20Sopenharmony_ci * allocs urbs and start isoc transfer with two pending urbs to avoid 13778c2ecf20Sopenharmony_ci * gaps in the transfer chain 13788c2ecf20Sopenharmony_ci */ 13798c2ecf20Sopenharmony_cistatic int 13808c2ecf20Sopenharmony_cistart_isoc_chain(struct usb_fifo *fifo, int num_packets_per_urb, 13818c2ecf20Sopenharmony_ci usb_complete_t complete, int packet_size) 13828c2ecf20Sopenharmony_ci{ 13838c2ecf20Sopenharmony_ci struct hfcsusb *hw = fifo->hw; 13848c2ecf20Sopenharmony_ci int i, k, errcode; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (debug) 13878c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: fifo %i\n", 13888c2ecf20Sopenharmony_ci hw->name, __func__, fifo->fifonum); 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci /* allocate Memory for Iso out Urbs */ 13918c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 13928c2ecf20Sopenharmony_ci if (!(fifo->iso[i].urb)) { 13938c2ecf20Sopenharmony_ci fifo->iso[i].urb = 13948c2ecf20Sopenharmony_ci usb_alloc_urb(num_packets_per_urb, GFP_KERNEL); 13958c2ecf20Sopenharmony_ci if (!(fifo->iso[i].urb)) { 13968c2ecf20Sopenharmony_ci printk(KERN_DEBUG 13978c2ecf20Sopenharmony_ci "%s: %s: alloc urb for fifo %i failed", 13988c2ecf20Sopenharmony_ci hw->name, __func__, fifo->fifonum); 13998c2ecf20Sopenharmony_ci continue; 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo; 14028c2ecf20Sopenharmony_ci fifo->iso[i].indx = i; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci /* Init the first iso */ 14058c2ecf20Sopenharmony_ci if (ISO_BUFFER_SIZE >= 14068c2ecf20Sopenharmony_ci (fifo->usb_packet_maxlen * 14078c2ecf20Sopenharmony_ci num_packets_per_urb)) { 14088c2ecf20Sopenharmony_ci fill_isoc_urb(fifo->iso[i].urb, 14098c2ecf20Sopenharmony_ci fifo->hw->dev, fifo->pipe, 14108c2ecf20Sopenharmony_ci fifo->iso[i].buffer, 14118c2ecf20Sopenharmony_ci num_packets_per_urb, 14128c2ecf20Sopenharmony_ci fifo->usb_packet_maxlen, 14138c2ecf20Sopenharmony_ci fifo->intervall, complete, 14148c2ecf20Sopenharmony_ci &fifo->iso[i]); 14158c2ecf20Sopenharmony_ci memset(fifo->iso[i].buffer, 0, 14168c2ecf20Sopenharmony_ci sizeof(fifo->iso[i].buffer)); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci for (k = 0; k < num_packets_per_urb; k++) { 14198c2ecf20Sopenharmony_ci fifo->iso[i].urb-> 14208c2ecf20Sopenharmony_ci iso_frame_desc[k].offset = 14218c2ecf20Sopenharmony_ci k * packet_size; 14228c2ecf20Sopenharmony_ci fifo->iso[i].urb-> 14238c2ecf20Sopenharmony_ci iso_frame_desc[k].length = 14248c2ecf20Sopenharmony_ci packet_size; 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci } else { 14278c2ecf20Sopenharmony_ci printk(KERN_DEBUG 14288c2ecf20Sopenharmony_ci "%s: %s: ISO Buffer size to small!\n", 14298c2ecf20Sopenharmony_ci hw->name, __func__); 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci fifo->bit_line = BITLINE_INF; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci errcode = usb_submit_urb(fifo->iso[i].urb, GFP_KERNEL); 14358c2ecf20Sopenharmony_ci fifo->active = (errcode >= 0) ? 1 : 0; 14368c2ecf20Sopenharmony_ci fifo->stop_gracefull = 0; 14378c2ecf20Sopenharmony_ci if (errcode < 0) { 14388c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: %s URB nr:%d\n", 14398c2ecf20Sopenharmony_ci hw->name, __func__, 14408c2ecf20Sopenharmony_ci symbolic(urb_errlist, errcode), i); 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci return fifo->active; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic void 14478c2ecf20Sopenharmony_cistop_iso_gracefull(struct usb_fifo *fifo) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci struct hfcsusb *hw = fifo->hw; 14508c2ecf20Sopenharmony_ci int i, timeout; 14518c2ecf20Sopenharmony_ci u_long flags; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 14548c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 14558c2ecf20Sopenharmony_ci if (debug) 14568c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s for fifo %i.%i\n", 14578c2ecf20Sopenharmony_ci hw->name, __func__, fifo->fifonum, i); 14588c2ecf20Sopenharmony_ci fifo->stop_gracefull = 1; 14598c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 14608c2ecf20Sopenharmony_ci } 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 14638c2ecf20Sopenharmony_ci timeout = 3; 14648c2ecf20Sopenharmony_ci while (fifo->stop_gracefull && timeout--) 14658c2ecf20Sopenharmony_ci schedule_timeout_interruptible((HZ / 1000) * 16); 14668c2ecf20Sopenharmony_ci if (debug && fifo->stop_gracefull) 14678c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: ERROR %s for fifo %i.%i\n", 14688c2ecf20Sopenharmony_ci hw->name, __func__, fifo->fifonum, i); 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci} 14718c2ecf20Sopenharmony_ci 14728c2ecf20Sopenharmony_cistatic void 14738c2ecf20Sopenharmony_cistop_int_gracefull(struct usb_fifo *fifo) 14748c2ecf20Sopenharmony_ci{ 14758c2ecf20Sopenharmony_ci struct hfcsusb *hw = fifo->hw; 14768c2ecf20Sopenharmony_ci int timeout; 14778c2ecf20Sopenharmony_ci u_long flags; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 14808c2ecf20Sopenharmony_ci if (debug) 14818c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s for fifo %i\n", 14828c2ecf20Sopenharmony_ci hw->name, __func__, fifo->fifonum); 14838c2ecf20Sopenharmony_ci fifo->stop_gracefull = 1; 14848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci timeout = 3; 14878c2ecf20Sopenharmony_ci while (fifo->stop_gracefull && timeout--) 14888c2ecf20Sopenharmony_ci schedule_timeout_interruptible((HZ / 1000) * 3); 14898c2ecf20Sopenharmony_ci if (debug && fifo->stop_gracefull) 14908c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: ERROR %s for fifo %i\n", 14918c2ecf20Sopenharmony_ci hw->name, __func__, fifo->fifonum); 14928c2ecf20Sopenharmony_ci} 14938c2ecf20Sopenharmony_ci 14948c2ecf20Sopenharmony_ci/* start the interrupt transfer for the given fifo */ 14958c2ecf20Sopenharmony_cistatic void 14968c2ecf20Sopenharmony_cistart_int_fifo(struct usb_fifo *fifo) 14978c2ecf20Sopenharmony_ci{ 14988c2ecf20Sopenharmony_ci struct hfcsusb *hw = fifo->hw; 14998c2ecf20Sopenharmony_ci int errcode; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if (debug) 15028c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: INT IN fifo:%d\n", 15038c2ecf20Sopenharmony_ci hw->name, __func__, fifo->fifonum); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci if (!fifo->urb) { 15068c2ecf20Sopenharmony_ci fifo->urb = usb_alloc_urb(0, GFP_KERNEL); 15078c2ecf20Sopenharmony_ci if (!fifo->urb) 15088c2ecf20Sopenharmony_ci return; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci usb_fill_int_urb(fifo->urb, fifo->hw->dev, fifo->pipe, 15118c2ecf20Sopenharmony_ci fifo->buffer, fifo->usb_packet_maxlen, 15128c2ecf20Sopenharmony_ci (usb_complete_t)rx_int_complete, fifo, fifo->intervall); 15138c2ecf20Sopenharmony_ci fifo->active = 1; 15148c2ecf20Sopenharmony_ci fifo->stop_gracefull = 0; 15158c2ecf20Sopenharmony_ci errcode = usb_submit_urb(fifo->urb, GFP_KERNEL); 15168c2ecf20Sopenharmony_ci if (errcode) { 15178c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: submit URB: status:%i\n", 15188c2ecf20Sopenharmony_ci hw->name, __func__, errcode); 15198c2ecf20Sopenharmony_ci fifo->active = 0; 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci} 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_cistatic void 15248c2ecf20Sopenharmony_cisetPortMode(struct hfcsusb *hw) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 15278c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s %s\n", hw->name, __func__, 15288c2ecf20Sopenharmony_ci (hw->protocol == ISDN_P_TE_S0) ? "TE" : "NT"); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci if (hw->protocol == ISDN_P_TE_S0) { 15318c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_SCTRL, 0x40); 15328c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_SCTRL_E, 0x00); 15338c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_CLKDEL, CLKDEL_TE); 15348c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, 3 | 0x10); 15358c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, 3); 15368c2ecf20Sopenharmony_ci } else { 15378c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_SCTRL, 0x44); 15388c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_SCTRL_E, 0x09); 15398c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_CLKDEL, CLKDEL_NT); 15408c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, 1 | 0x10); 15418c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_STATES, 1); 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci} 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_cistatic void 15468c2ecf20Sopenharmony_cireset_hfcsusb(struct hfcsusb *hw) 15478c2ecf20Sopenharmony_ci{ 15488c2ecf20Sopenharmony_ci struct usb_fifo *fifo; 15498c2ecf20Sopenharmony_ci int i; 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci if (debug & DEBUG_HW) 15528c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci /* do Chip reset */ 15558c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_CIRM, 8); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci /* aux = output, reset off */ 15588c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_CIRM, 0x10); 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci /* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */ 15618c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_USB_SIZE, (hw->packet_size / 8) | 15628c2ecf20Sopenharmony_ci ((hw->packet_size / 8) << 4)); 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci /* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */ 15658c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_USB_SIZE_I, hw->iso_packet_size); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci /* enable PCM/GCI master mode */ 15688c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_MST_MODE1, 0); /* set default values */ 15698c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_MST_MODE0, 1); /* enable master mode */ 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci /* init the fifos */ 15728c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_F_THRES, 15738c2ecf20Sopenharmony_ci (HFCUSB_TX_THRESHOLD / 8) | ((HFCUSB_RX_THRESHOLD / 8) << 4)); 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci fifo = hw->fifos; 15768c2ecf20Sopenharmony_ci for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { 15778c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_FIFO, i); /* select the desired fifo */ 15788c2ecf20Sopenharmony_ci fifo[i].max_size = 15798c2ecf20Sopenharmony_ci (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN; 15808c2ecf20Sopenharmony_ci fifo[i].last_urblen = 0; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci /* set 2 bit for D- & E-channel */ 15838c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2)); 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci /* enable all fifos */ 15868c2ecf20Sopenharmony_ci if (i == HFCUSB_D_TX) 15878c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_CON_HDLC, 15888c2ecf20Sopenharmony_ci (hw->protocol == ISDN_P_NT_S0) ? 0x08 : 0x09); 15898c2ecf20Sopenharmony_ci else 15908c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_CON_HDLC, 0x08); 15918c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_INC_RES_F, 2); /* reset the fifo */ 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci write_reg(hw, HFCUSB_SCTRL_R, 0); /* disable both B receivers */ 15958c2ecf20Sopenharmony_ci handle_led(hw, LED_POWER_ON); 15968c2ecf20Sopenharmony_ci} 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci/* start USB data pipes dependand on device's endpoint configuration */ 15998c2ecf20Sopenharmony_cistatic void 16008c2ecf20Sopenharmony_cihfcsusb_start_endpoint(struct hfcsusb *hw, int channel) 16018c2ecf20Sopenharmony_ci{ 16028c2ecf20Sopenharmony_ci /* quick check if endpoint already running */ 16038c2ecf20Sopenharmony_ci if ((channel == HFC_CHAN_D) && (hw->fifos[HFCUSB_D_RX].active)) 16048c2ecf20Sopenharmony_ci return; 16058c2ecf20Sopenharmony_ci if ((channel == HFC_CHAN_B1) && (hw->fifos[HFCUSB_B1_RX].active)) 16068c2ecf20Sopenharmony_ci return; 16078c2ecf20Sopenharmony_ci if ((channel == HFC_CHAN_B2) && (hw->fifos[HFCUSB_B2_RX].active)) 16088c2ecf20Sopenharmony_ci return; 16098c2ecf20Sopenharmony_ci if ((channel == HFC_CHAN_E) && (hw->fifos[HFCUSB_PCM_RX].active)) 16108c2ecf20Sopenharmony_ci return; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci /* start rx endpoints using USB INT IN method */ 16138c2ecf20Sopenharmony_ci if (hw->cfg_used == CNF_3INT3ISO || hw->cfg_used == CNF_4INT3ISO) 16148c2ecf20Sopenharmony_ci start_int_fifo(hw->fifos + channel * 2 + 1); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci /* start rx endpoints using USB ISO IN method */ 16178c2ecf20Sopenharmony_ci if (hw->cfg_used == CNF_3ISO3ISO || hw->cfg_used == CNF_4ISO3ISO) { 16188c2ecf20Sopenharmony_ci switch (channel) { 16198c2ecf20Sopenharmony_ci case HFC_CHAN_D: 16208c2ecf20Sopenharmony_ci start_isoc_chain(hw->fifos + HFCUSB_D_RX, 16218c2ecf20Sopenharmony_ci ISOC_PACKETS_D, 16228c2ecf20Sopenharmony_ci (usb_complete_t)rx_iso_complete, 16238c2ecf20Sopenharmony_ci 16); 16248c2ecf20Sopenharmony_ci break; 16258c2ecf20Sopenharmony_ci case HFC_CHAN_E: 16268c2ecf20Sopenharmony_ci start_isoc_chain(hw->fifos + HFCUSB_PCM_RX, 16278c2ecf20Sopenharmony_ci ISOC_PACKETS_D, 16288c2ecf20Sopenharmony_ci (usb_complete_t)rx_iso_complete, 16298c2ecf20Sopenharmony_ci 16); 16308c2ecf20Sopenharmony_ci break; 16318c2ecf20Sopenharmony_ci case HFC_CHAN_B1: 16328c2ecf20Sopenharmony_ci start_isoc_chain(hw->fifos + HFCUSB_B1_RX, 16338c2ecf20Sopenharmony_ci ISOC_PACKETS_B, 16348c2ecf20Sopenharmony_ci (usb_complete_t)rx_iso_complete, 16358c2ecf20Sopenharmony_ci 16); 16368c2ecf20Sopenharmony_ci break; 16378c2ecf20Sopenharmony_ci case HFC_CHAN_B2: 16388c2ecf20Sopenharmony_ci start_isoc_chain(hw->fifos + HFCUSB_B2_RX, 16398c2ecf20Sopenharmony_ci ISOC_PACKETS_B, 16408c2ecf20Sopenharmony_ci (usb_complete_t)rx_iso_complete, 16418c2ecf20Sopenharmony_ci 16); 16428c2ecf20Sopenharmony_ci break; 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci /* start tx endpoints using USB ISO OUT method */ 16478c2ecf20Sopenharmony_ci switch (channel) { 16488c2ecf20Sopenharmony_ci case HFC_CHAN_D: 16498c2ecf20Sopenharmony_ci start_isoc_chain(hw->fifos + HFCUSB_D_TX, 16508c2ecf20Sopenharmony_ci ISOC_PACKETS_B, 16518c2ecf20Sopenharmony_ci (usb_complete_t)tx_iso_complete, 1); 16528c2ecf20Sopenharmony_ci break; 16538c2ecf20Sopenharmony_ci case HFC_CHAN_B1: 16548c2ecf20Sopenharmony_ci start_isoc_chain(hw->fifos + HFCUSB_B1_TX, 16558c2ecf20Sopenharmony_ci ISOC_PACKETS_D, 16568c2ecf20Sopenharmony_ci (usb_complete_t)tx_iso_complete, 1); 16578c2ecf20Sopenharmony_ci break; 16588c2ecf20Sopenharmony_ci case HFC_CHAN_B2: 16598c2ecf20Sopenharmony_ci start_isoc_chain(hw->fifos + HFCUSB_B2_TX, 16608c2ecf20Sopenharmony_ci ISOC_PACKETS_B, 16618c2ecf20Sopenharmony_ci (usb_complete_t)tx_iso_complete, 1); 16628c2ecf20Sopenharmony_ci break; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci} 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci/* stop USB data pipes dependand on device's endpoint configuration */ 16678c2ecf20Sopenharmony_cistatic void 16688c2ecf20Sopenharmony_cihfcsusb_stop_endpoint(struct hfcsusb *hw, int channel) 16698c2ecf20Sopenharmony_ci{ 16708c2ecf20Sopenharmony_ci /* quick check if endpoint currently running */ 16718c2ecf20Sopenharmony_ci if ((channel == HFC_CHAN_D) && (!hw->fifos[HFCUSB_D_RX].active)) 16728c2ecf20Sopenharmony_ci return; 16738c2ecf20Sopenharmony_ci if ((channel == HFC_CHAN_B1) && (!hw->fifos[HFCUSB_B1_RX].active)) 16748c2ecf20Sopenharmony_ci return; 16758c2ecf20Sopenharmony_ci if ((channel == HFC_CHAN_B2) && (!hw->fifos[HFCUSB_B2_RX].active)) 16768c2ecf20Sopenharmony_ci return; 16778c2ecf20Sopenharmony_ci if ((channel == HFC_CHAN_E) && (!hw->fifos[HFCUSB_PCM_RX].active)) 16788c2ecf20Sopenharmony_ci return; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci /* rx endpoints using USB INT IN method */ 16818c2ecf20Sopenharmony_ci if (hw->cfg_used == CNF_3INT3ISO || hw->cfg_used == CNF_4INT3ISO) 16828c2ecf20Sopenharmony_ci stop_int_gracefull(hw->fifos + channel * 2 + 1); 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci /* rx endpoints using USB ISO IN method */ 16858c2ecf20Sopenharmony_ci if (hw->cfg_used == CNF_3ISO3ISO || hw->cfg_used == CNF_4ISO3ISO) 16868c2ecf20Sopenharmony_ci stop_iso_gracefull(hw->fifos + channel * 2 + 1); 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci /* tx endpoints using USB ISO OUT method */ 16898c2ecf20Sopenharmony_ci if (channel != HFC_CHAN_E) 16908c2ecf20Sopenharmony_ci stop_iso_gracefull(hw->fifos + channel * 2); 16918c2ecf20Sopenharmony_ci} 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci/* Hardware Initialization */ 16958c2ecf20Sopenharmony_cistatic int 16968c2ecf20Sopenharmony_cisetup_hfcsusb(struct hfcsusb *hw) 16978c2ecf20Sopenharmony_ci{ 16988c2ecf20Sopenharmony_ci void *dmabuf = kmalloc(sizeof(u_char), GFP_KERNEL); 16998c2ecf20Sopenharmony_ci u_char b; 17008c2ecf20Sopenharmony_ci int ret; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 17038c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (!dmabuf) 17068c2ecf20Sopenharmony_ci return -ENOMEM; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci ret = read_reg_atomic(hw, HFCUSB_CHIP_ID, dmabuf); 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci memcpy(&b, dmabuf, sizeof(u_char)); 17118c2ecf20Sopenharmony_ci kfree(dmabuf); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci /* check the chip id */ 17148c2ecf20Sopenharmony_ci if (ret != 1) { 17158c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: cannot read chip id\n", 17168c2ecf20Sopenharmony_ci hw->name, __func__); 17178c2ecf20Sopenharmony_ci return 1; 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci if (b != HFCUSB_CHIPID) { 17208c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: Invalid chip id 0x%02x\n", 17218c2ecf20Sopenharmony_ci hw->name, __func__, b); 17228c2ecf20Sopenharmony_ci return 1; 17238c2ecf20Sopenharmony_ci } 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci /* first set the needed config, interface and alternate */ 17268c2ecf20Sopenharmony_ci (void) usb_set_interface(hw->dev, hw->if_used, hw->alt_used); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci hw->led_state = 0; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci /* init the background machinery for control requests */ 17318c2ecf20Sopenharmony_ci hw->ctrl_read.bRequestType = 0xc0; 17328c2ecf20Sopenharmony_ci hw->ctrl_read.bRequest = 1; 17338c2ecf20Sopenharmony_ci hw->ctrl_read.wLength = cpu_to_le16(1); 17348c2ecf20Sopenharmony_ci hw->ctrl_write.bRequestType = 0x40; 17358c2ecf20Sopenharmony_ci hw->ctrl_write.bRequest = 0; 17368c2ecf20Sopenharmony_ci hw->ctrl_write.wLength = 0; 17378c2ecf20Sopenharmony_ci usb_fill_control_urb(hw->ctrl_urb, hw->dev, hw->ctrl_out_pipe, 17388c2ecf20Sopenharmony_ci (u_char *)&hw->ctrl_write, NULL, 0, 17398c2ecf20Sopenharmony_ci (usb_complete_t)ctrl_complete, hw); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci reset_hfcsusb(hw); 17428c2ecf20Sopenharmony_ci return 0; 17438c2ecf20Sopenharmony_ci} 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_cistatic void 17468c2ecf20Sopenharmony_cirelease_hw(struct hfcsusb *hw) 17478c2ecf20Sopenharmony_ci{ 17488c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 17498c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci /* 17528c2ecf20Sopenharmony_ci * stop all endpoints gracefully 17538c2ecf20Sopenharmony_ci * TODO: mISDN_core should generate CLOSE_CHANNEL 17548c2ecf20Sopenharmony_ci * signals after calling mISDN_unregister_device() 17558c2ecf20Sopenharmony_ci */ 17568c2ecf20Sopenharmony_ci hfcsusb_stop_endpoint(hw, HFC_CHAN_D); 17578c2ecf20Sopenharmony_ci hfcsusb_stop_endpoint(hw, HFC_CHAN_B1); 17588c2ecf20Sopenharmony_ci hfcsusb_stop_endpoint(hw, HFC_CHAN_B2); 17598c2ecf20Sopenharmony_ci if (hw->fifos[HFCUSB_PCM_RX].pipe) 17608c2ecf20Sopenharmony_ci hfcsusb_stop_endpoint(hw, HFC_CHAN_E); 17618c2ecf20Sopenharmony_ci if (hw->protocol == ISDN_P_TE_S0) 17628c2ecf20Sopenharmony_ci l1_event(hw->dch.l1, CLOSE_CHANNEL); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci mISDN_unregister_device(&hw->dch.dev); 17658c2ecf20Sopenharmony_ci mISDN_freebchannel(&hw->bch[1]); 17668c2ecf20Sopenharmony_ci mISDN_freebchannel(&hw->bch[0]); 17678c2ecf20Sopenharmony_ci mISDN_freedchannel(&hw->dch); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci if (hw->ctrl_urb) { 17708c2ecf20Sopenharmony_ci usb_kill_urb(hw->ctrl_urb); 17718c2ecf20Sopenharmony_ci usb_free_urb(hw->ctrl_urb); 17728c2ecf20Sopenharmony_ci hw->ctrl_urb = NULL; 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci if (hw->intf) 17768c2ecf20Sopenharmony_ci usb_set_intfdata(hw->intf, NULL); 17778c2ecf20Sopenharmony_ci list_del(&hw->list); 17788c2ecf20Sopenharmony_ci kfree(hw); 17798c2ecf20Sopenharmony_ci hw = NULL; 17808c2ecf20Sopenharmony_ci} 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_cistatic void 17838c2ecf20Sopenharmony_cideactivate_bchannel(struct bchannel *bch) 17848c2ecf20Sopenharmony_ci{ 17858c2ecf20Sopenharmony_ci struct hfcsusb *hw = bch->hw; 17868c2ecf20Sopenharmony_ci u_long flags; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW) 17898c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s: bch->nr(%i)\n", 17908c2ecf20Sopenharmony_ci hw->name, __func__, bch->nr); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci spin_lock_irqsave(&hw->lock, flags); 17938c2ecf20Sopenharmony_ci mISDN_clear_bchannel(bch); 17948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hw->lock, flags); 17958c2ecf20Sopenharmony_ci hfcsusb_setup_bch(bch, ISDN_P_NONE); 17968c2ecf20Sopenharmony_ci hfcsusb_stop_endpoint(hw, bch->nr - 1); 17978c2ecf20Sopenharmony_ci} 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci/* 18008c2ecf20Sopenharmony_ci * Layer 1 B-channel hardware access 18018c2ecf20Sopenharmony_ci */ 18028c2ecf20Sopenharmony_cistatic int 18038c2ecf20Sopenharmony_cihfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) 18048c2ecf20Sopenharmony_ci{ 18058c2ecf20Sopenharmony_ci struct bchannel *bch = container_of(ch, struct bchannel, ch); 18068c2ecf20Sopenharmony_ci int ret = -EINVAL; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci if (bch->debug & DEBUG_HW) 18098c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg); 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci switch (cmd) { 18128c2ecf20Sopenharmony_ci case HW_TESTRX_RAW: 18138c2ecf20Sopenharmony_ci case HW_TESTRX_HDLC: 18148c2ecf20Sopenharmony_ci case HW_TESTRX_OFF: 18158c2ecf20Sopenharmony_ci ret = -EINVAL; 18168c2ecf20Sopenharmony_ci break; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci case CLOSE_CHANNEL: 18198c2ecf20Sopenharmony_ci test_and_clear_bit(FLG_OPEN, &bch->Flags); 18208c2ecf20Sopenharmony_ci deactivate_bchannel(bch); 18218c2ecf20Sopenharmony_ci ch->protocol = ISDN_P_NONE; 18228c2ecf20Sopenharmony_ci ch->peer = NULL; 18238c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 18248c2ecf20Sopenharmony_ci ret = 0; 18258c2ecf20Sopenharmony_ci break; 18268c2ecf20Sopenharmony_ci case CONTROL_CHANNEL: 18278c2ecf20Sopenharmony_ci ret = channel_bctrl(bch, arg); 18288c2ecf20Sopenharmony_ci break; 18298c2ecf20Sopenharmony_ci default: 18308c2ecf20Sopenharmony_ci printk(KERN_WARNING "%s: unknown prim(%x)\n", 18318c2ecf20Sopenharmony_ci __func__, cmd); 18328c2ecf20Sopenharmony_ci } 18338c2ecf20Sopenharmony_ci return ret; 18348c2ecf20Sopenharmony_ci} 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_cistatic int 18378c2ecf20Sopenharmony_cisetup_instance(struct hfcsusb *hw, struct device *parent) 18388c2ecf20Sopenharmony_ci{ 18398c2ecf20Sopenharmony_ci u_long flags; 18408c2ecf20Sopenharmony_ci int err, i; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci if (debug & DBG_HFC_CALL_TRACE) 18438c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci spin_lock_init(&hw->ctrl_lock); 18468c2ecf20Sopenharmony_ci spin_lock_init(&hw->lock); 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci mISDN_initdchannel(&hw->dch, MAX_DFRAME_LEN_L1, ph_state); 18498c2ecf20Sopenharmony_ci hw->dch.debug = debug & 0xFFFF; 18508c2ecf20Sopenharmony_ci hw->dch.hw = hw; 18518c2ecf20Sopenharmony_ci hw->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); 18528c2ecf20Sopenharmony_ci hw->dch.dev.D.send = hfcusb_l2l1D; 18538c2ecf20Sopenharmony_ci hw->dch.dev.D.ctrl = hfc_dctrl; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci /* enable E-Channel logging */ 18568c2ecf20Sopenharmony_ci if (hw->fifos[HFCUSB_PCM_RX].pipe) 18578c2ecf20Sopenharmony_ci mISDN_initdchannel(&hw->ech, MAX_DFRAME_LEN_L1, NULL); 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci hw->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | 18608c2ecf20Sopenharmony_ci (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); 18618c2ecf20Sopenharmony_ci hw->dch.dev.nrbchan = 2; 18628c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 18638c2ecf20Sopenharmony_ci hw->bch[i].nr = i + 1; 18648c2ecf20Sopenharmony_ci set_channelmap(i + 1, hw->dch.dev.channelmap); 18658c2ecf20Sopenharmony_ci hw->bch[i].debug = debug; 18668c2ecf20Sopenharmony_ci mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM, poll >> 1); 18678c2ecf20Sopenharmony_ci hw->bch[i].hw = hw; 18688c2ecf20Sopenharmony_ci hw->bch[i].ch.send = hfcusb_l2l1B; 18698c2ecf20Sopenharmony_ci hw->bch[i].ch.ctrl = hfc_bctrl; 18708c2ecf20Sopenharmony_ci hw->bch[i].ch.nr = i + 1; 18718c2ecf20Sopenharmony_ci list_add(&hw->bch[i].ch.list, &hw->dch.dev.bchannels); 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci hw->fifos[HFCUSB_B1_TX].bch = &hw->bch[0]; 18758c2ecf20Sopenharmony_ci hw->fifos[HFCUSB_B1_RX].bch = &hw->bch[0]; 18768c2ecf20Sopenharmony_ci hw->fifos[HFCUSB_B2_TX].bch = &hw->bch[1]; 18778c2ecf20Sopenharmony_ci hw->fifos[HFCUSB_B2_RX].bch = &hw->bch[1]; 18788c2ecf20Sopenharmony_ci hw->fifos[HFCUSB_D_TX].dch = &hw->dch; 18798c2ecf20Sopenharmony_ci hw->fifos[HFCUSB_D_RX].dch = &hw->dch; 18808c2ecf20Sopenharmony_ci hw->fifos[HFCUSB_PCM_RX].ech = &hw->ech; 18818c2ecf20Sopenharmony_ci hw->fifos[HFCUSB_PCM_TX].ech = &hw->ech; 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci err = setup_hfcsusb(hw); 18848c2ecf20Sopenharmony_ci if (err) 18858c2ecf20Sopenharmony_ci goto out; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci snprintf(hw->name, MISDN_MAX_IDLEN - 1, "%s.%d", DRIVER_NAME, 18888c2ecf20Sopenharmony_ci hfcsusb_cnt + 1); 18898c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: registered as '%s'\n", 18908c2ecf20Sopenharmony_ci DRIVER_NAME, hw->name); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci err = mISDN_register_device(&hw->dch.dev, parent, hw->name); 18938c2ecf20Sopenharmony_ci if (err) 18948c2ecf20Sopenharmony_ci goto out; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci hfcsusb_cnt++; 18978c2ecf20Sopenharmony_ci write_lock_irqsave(&HFClock, flags); 18988c2ecf20Sopenharmony_ci list_add_tail(&hw->list, &HFClist); 18998c2ecf20Sopenharmony_ci write_unlock_irqrestore(&HFClock, flags); 19008c2ecf20Sopenharmony_ci return 0; 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ciout: 19038c2ecf20Sopenharmony_ci mISDN_freebchannel(&hw->bch[1]); 19048c2ecf20Sopenharmony_ci mISDN_freebchannel(&hw->bch[0]); 19058c2ecf20Sopenharmony_ci mISDN_freedchannel(&hw->dch); 19068c2ecf20Sopenharmony_ci kfree(hw); 19078c2ecf20Sopenharmony_ci return err; 19088c2ecf20Sopenharmony_ci} 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_cistatic int 19118c2ecf20Sopenharmony_cihfcsusb_probe(struct usb_interface *intf, const struct usb_device_id *id) 19128c2ecf20Sopenharmony_ci{ 19138c2ecf20Sopenharmony_ci struct hfcsusb *hw; 19148c2ecf20Sopenharmony_ci struct usb_device *dev = interface_to_usbdev(intf); 19158c2ecf20Sopenharmony_ci struct usb_host_interface *iface = intf->cur_altsetting; 19168c2ecf20Sopenharmony_ci struct usb_host_interface *iface_used = NULL; 19178c2ecf20Sopenharmony_ci struct usb_host_endpoint *ep; 19188c2ecf20Sopenharmony_ci struct hfcsusb_vdata *driver_info; 19198c2ecf20Sopenharmony_ci int ifnum = iface->desc.bInterfaceNumber, i, idx, alt_idx, 19208c2ecf20Sopenharmony_ci probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found, 19218c2ecf20Sopenharmony_ci ep_addr, cmptbl[16], small_match, iso_packet_size, packet_size, 19228c2ecf20Sopenharmony_ci alt_used = 0; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci vend_idx = 0xffff; 19258c2ecf20Sopenharmony_ci for (i = 0; hfcsusb_idtab[i].idVendor; i++) { 19268c2ecf20Sopenharmony_ci if ((le16_to_cpu(dev->descriptor.idVendor) 19278c2ecf20Sopenharmony_ci == hfcsusb_idtab[i].idVendor) && 19288c2ecf20Sopenharmony_ci (le16_to_cpu(dev->descriptor.idProduct) 19298c2ecf20Sopenharmony_ci == hfcsusb_idtab[i].idProduct)) { 19308c2ecf20Sopenharmony_ci vend_idx = i; 19318c2ecf20Sopenharmony_ci continue; 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci } 19348c2ecf20Sopenharmony_ci 19358c2ecf20Sopenharmony_ci printk(KERN_DEBUG 19368c2ecf20Sopenharmony_ci "%s: interface(%d) actalt(%d) minor(%d) vend_idx(%d)\n", 19378c2ecf20Sopenharmony_ci __func__, ifnum, iface->desc.bAlternateSetting, 19388c2ecf20Sopenharmony_ci intf->minor, vend_idx); 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci if (vend_idx == 0xffff) { 19418c2ecf20Sopenharmony_ci printk(KERN_WARNING 19428c2ecf20Sopenharmony_ci "%s: no valid vendor found in USB descriptor\n", 19438c2ecf20Sopenharmony_ci __func__); 19448c2ecf20Sopenharmony_ci return -EIO; 19458c2ecf20Sopenharmony_ci } 19468c2ecf20Sopenharmony_ci /* if vendor and product ID is OK, start probing alternate settings */ 19478c2ecf20Sopenharmony_ci alt_idx = 0; 19488c2ecf20Sopenharmony_ci small_match = -1; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci /* default settings */ 19518c2ecf20Sopenharmony_ci iso_packet_size = 16; 19528c2ecf20Sopenharmony_ci packet_size = 64; 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci while (alt_idx < intf->num_altsetting) { 19558c2ecf20Sopenharmony_ci iface = intf->altsetting + alt_idx; 19568c2ecf20Sopenharmony_ci probe_alt_setting = iface->desc.bAlternateSetting; 19578c2ecf20Sopenharmony_ci cfg_used = 0; 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci while (validconf[cfg_used][0]) { 19608c2ecf20Sopenharmony_ci cfg_found = 1; 19618c2ecf20Sopenharmony_ci vcf = validconf[cfg_used]; 19628c2ecf20Sopenharmony_ci ep = iface->endpoint; 19638c2ecf20Sopenharmony_ci memcpy(cmptbl, vcf, 16 * sizeof(int)); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci /* check for all endpoints in this alternate setting */ 19668c2ecf20Sopenharmony_ci for (i = 0; i < iface->desc.bNumEndpoints; i++) { 19678c2ecf20Sopenharmony_ci ep_addr = ep->desc.bEndpointAddress; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci /* get endpoint base */ 19708c2ecf20Sopenharmony_ci idx = ((ep_addr & 0x7f) - 1) * 2; 19718c2ecf20Sopenharmony_ci if (idx > 15) 19728c2ecf20Sopenharmony_ci return -EIO; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci if (ep_addr & 0x80) 19758c2ecf20Sopenharmony_ci idx++; 19768c2ecf20Sopenharmony_ci attr = ep->desc.bmAttributes; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (cmptbl[idx] != EP_NOP) { 19798c2ecf20Sopenharmony_ci if (cmptbl[idx] == EP_NUL) 19808c2ecf20Sopenharmony_ci cfg_found = 0; 19818c2ecf20Sopenharmony_ci if (attr == USB_ENDPOINT_XFER_INT 19828c2ecf20Sopenharmony_ci && cmptbl[idx] == EP_INT) 19838c2ecf20Sopenharmony_ci cmptbl[idx] = EP_NUL; 19848c2ecf20Sopenharmony_ci if (attr == USB_ENDPOINT_XFER_BULK 19858c2ecf20Sopenharmony_ci && cmptbl[idx] == EP_BLK) 19868c2ecf20Sopenharmony_ci cmptbl[idx] = EP_NUL; 19878c2ecf20Sopenharmony_ci if (attr == USB_ENDPOINT_XFER_ISOC 19888c2ecf20Sopenharmony_ci && cmptbl[idx] == EP_ISO) 19898c2ecf20Sopenharmony_ci cmptbl[idx] = EP_NUL; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci if (attr == USB_ENDPOINT_XFER_INT && 19928c2ecf20Sopenharmony_ci ep->desc.bInterval < vcf[17]) { 19938c2ecf20Sopenharmony_ci cfg_found = 0; 19948c2ecf20Sopenharmony_ci } 19958c2ecf20Sopenharmony_ci } 19968c2ecf20Sopenharmony_ci ep++; 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) 20008c2ecf20Sopenharmony_ci if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL) 20018c2ecf20Sopenharmony_ci cfg_found = 0; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci if (cfg_found) { 20048c2ecf20Sopenharmony_ci if (small_match < cfg_used) { 20058c2ecf20Sopenharmony_ci small_match = cfg_used; 20068c2ecf20Sopenharmony_ci alt_used = probe_alt_setting; 20078c2ecf20Sopenharmony_ci iface_used = iface; 20088c2ecf20Sopenharmony_ci } 20098c2ecf20Sopenharmony_ci } 20108c2ecf20Sopenharmony_ci cfg_used++; 20118c2ecf20Sopenharmony_ci } 20128c2ecf20Sopenharmony_ci alt_idx++; 20138c2ecf20Sopenharmony_ci } /* (alt_idx < intf->num_altsetting) */ 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci /* not found a valid USB Ta Endpoint config */ 20168c2ecf20Sopenharmony_ci if (small_match == -1) 20178c2ecf20Sopenharmony_ci return -EIO; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci iface = iface_used; 20208c2ecf20Sopenharmony_ci hw = kzalloc(sizeof(struct hfcsusb), GFP_KERNEL); 20218c2ecf20Sopenharmony_ci if (!hw) 20228c2ecf20Sopenharmony_ci return -ENOMEM; /* got no mem */ 20238c2ecf20Sopenharmony_ci snprintf(hw->name, MISDN_MAX_IDLEN - 1, "%s", DRIVER_NAME); 20248c2ecf20Sopenharmony_ci 20258c2ecf20Sopenharmony_ci ep = iface->endpoint; 20268c2ecf20Sopenharmony_ci vcf = validconf[small_match]; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci for (i = 0; i < iface->desc.bNumEndpoints; i++) { 20298c2ecf20Sopenharmony_ci struct usb_fifo *f; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci ep_addr = ep->desc.bEndpointAddress; 20328c2ecf20Sopenharmony_ci /* get endpoint base */ 20338c2ecf20Sopenharmony_ci idx = ((ep_addr & 0x7f) - 1) * 2; 20348c2ecf20Sopenharmony_ci if (ep_addr & 0x80) 20358c2ecf20Sopenharmony_ci idx++; 20368c2ecf20Sopenharmony_ci f = &hw->fifos[idx & 7]; 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci /* init Endpoints */ 20398c2ecf20Sopenharmony_ci if (vcf[idx] == EP_NOP || vcf[idx] == EP_NUL) { 20408c2ecf20Sopenharmony_ci ep++; 20418c2ecf20Sopenharmony_ci continue; 20428c2ecf20Sopenharmony_ci } 20438c2ecf20Sopenharmony_ci switch (ep->desc.bmAttributes) { 20448c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_INT: 20458c2ecf20Sopenharmony_ci f->pipe = usb_rcvintpipe(dev, 20468c2ecf20Sopenharmony_ci ep->desc.bEndpointAddress); 20478c2ecf20Sopenharmony_ci f->usb_transfer_mode = USB_INT; 20488c2ecf20Sopenharmony_ci packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); 20498c2ecf20Sopenharmony_ci break; 20508c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_BULK: 20518c2ecf20Sopenharmony_ci if (ep_addr & 0x80) 20528c2ecf20Sopenharmony_ci f->pipe = usb_rcvbulkpipe(dev, 20538c2ecf20Sopenharmony_ci ep->desc.bEndpointAddress); 20548c2ecf20Sopenharmony_ci else 20558c2ecf20Sopenharmony_ci f->pipe = usb_sndbulkpipe(dev, 20568c2ecf20Sopenharmony_ci ep->desc.bEndpointAddress); 20578c2ecf20Sopenharmony_ci f->usb_transfer_mode = USB_BULK; 20588c2ecf20Sopenharmony_ci packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); 20598c2ecf20Sopenharmony_ci break; 20608c2ecf20Sopenharmony_ci case USB_ENDPOINT_XFER_ISOC: 20618c2ecf20Sopenharmony_ci if (ep_addr & 0x80) 20628c2ecf20Sopenharmony_ci f->pipe = usb_rcvisocpipe(dev, 20638c2ecf20Sopenharmony_ci ep->desc.bEndpointAddress); 20648c2ecf20Sopenharmony_ci else 20658c2ecf20Sopenharmony_ci f->pipe = usb_sndisocpipe(dev, 20668c2ecf20Sopenharmony_ci ep->desc.bEndpointAddress); 20678c2ecf20Sopenharmony_ci f->usb_transfer_mode = USB_ISOC; 20688c2ecf20Sopenharmony_ci iso_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); 20698c2ecf20Sopenharmony_ci break; 20708c2ecf20Sopenharmony_ci default: 20718c2ecf20Sopenharmony_ci f->pipe = 0; 20728c2ecf20Sopenharmony_ci } 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci if (f->pipe) { 20758c2ecf20Sopenharmony_ci f->fifonum = idx & 7; 20768c2ecf20Sopenharmony_ci f->hw = hw; 20778c2ecf20Sopenharmony_ci f->usb_packet_maxlen = 20788c2ecf20Sopenharmony_ci le16_to_cpu(ep->desc.wMaxPacketSize); 20798c2ecf20Sopenharmony_ci f->intervall = ep->desc.bInterval; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci ep++; 20828c2ecf20Sopenharmony_ci } 20838c2ecf20Sopenharmony_ci hw->dev = dev; /* save device */ 20848c2ecf20Sopenharmony_ci hw->if_used = ifnum; /* save used interface */ 20858c2ecf20Sopenharmony_ci hw->alt_used = alt_used; /* and alternate config */ 20868c2ecf20Sopenharmony_ci hw->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */ 20878c2ecf20Sopenharmony_ci hw->cfg_used = vcf[16]; /* store used config */ 20888c2ecf20Sopenharmony_ci hw->vend_idx = vend_idx; /* store found vendor */ 20898c2ecf20Sopenharmony_ci hw->packet_size = packet_size; 20908c2ecf20Sopenharmony_ci hw->iso_packet_size = iso_packet_size; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci /* create the control pipes needed for register access */ 20938c2ecf20Sopenharmony_ci hw->ctrl_in_pipe = usb_rcvctrlpipe(hw->dev, 0); 20948c2ecf20Sopenharmony_ci hw->ctrl_out_pipe = usb_sndctrlpipe(hw->dev, 0); 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci driver_info = (struct hfcsusb_vdata *) 20978c2ecf20Sopenharmony_ci hfcsusb_idtab[vend_idx].driver_info; 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci hw->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); 21008c2ecf20Sopenharmony_ci if (!hw->ctrl_urb) { 21018c2ecf20Sopenharmony_ci pr_warn("%s: No memory for control urb\n", 21028c2ecf20Sopenharmony_ci driver_info->vend_name); 21038c2ecf20Sopenharmony_ci kfree(hw); 21048c2ecf20Sopenharmony_ci return -ENOMEM; 21058c2ecf20Sopenharmony_ci } 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci pr_info("%s: %s: detected \"%s\" (%s, if=%d alt=%d)\n", 21088c2ecf20Sopenharmony_ci hw->name, __func__, driver_info->vend_name, 21098c2ecf20Sopenharmony_ci conf_str[small_match], ifnum, alt_used); 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci if (setup_instance(hw, dev->dev.parent)) 21128c2ecf20Sopenharmony_ci return -EIO; 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci hw->intf = intf; 21158c2ecf20Sopenharmony_ci usb_set_intfdata(hw->intf, hw); 21168c2ecf20Sopenharmony_ci return 0; 21178c2ecf20Sopenharmony_ci} 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci/* function called when an active device is removed */ 21208c2ecf20Sopenharmony_cistatic void 21218c2ecf20Sopenharmony_cihfcsusb_disconnect(struct usb_interface *intf) 21228c2ecf20Sopenharmony_ci{ 21238c2ecf20Sopenharmony_ci struct hfcsusb *hw = usb_get_intfdata(intf); 21248c2ecf20Sopenharmony_ci struct hfcsusb *next; 21258c2ecf20Sopenharmony_ci int cnt = 0; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: device disconnected\n", hw->name); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci handle_led(hw, LED_POWER_OFF); 21308c2ecf20Sopenharmony_ci release_hw(hw); 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci list_for_each_entry_safe(hw, next, &HFClist, list) 21338c2ecf20Sopenharmony_ci cnt++; 21348c2ecf20Sopenharmony_ci if (!cnt) 21358c2ecf20Sopenharmony_ci hfcsusb_cnt = 0; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci usb_set_intfdata(intf, NULL); 21388c2ecf20Sopenharmony_ci} 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_cistatic struct usb_driver hfcsusb_drv = { 21418c2ecf20Sopenharmony_ci .name = DRIVER_NAME, 21428c2ecf20Sopenharmony_ci .id_table = hfcsusb_idtab, 21438c2ecf20Sopenharmony_ci .probe = hfcsusb_probe, 21448c2ecf20Sopenharmony_ci .disconnect = hfcsusb_disconnect, 21458c2ecf20Sopenharmony_ci .disable_hub_initiated_lpm = 1, 21468c2ecf20Sopenharmony_ci}; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_cimodule_usb_driver(hfcsusb_drv); 2149