linux/drivers/isdn/hisax/st5481_b.c
<<
>>
Prefs
   1/*
   2 * Driver for ST5481 USB ISDN modem
   3 *
   4 * Author       Frode Isaksen
   5 * Copyright    2001 by Frode Isaksen      <fisaksen@bewan.com>
   6 *              2001 by Kai Germaschewski  <kai.germaschewski@gmx.de>
   7 *
   8 * This software may be used and distributed according to the terms
   9 * of the GNU General Public License, incorporated herein by reference.
  10 *
  11 */
  12
  13#include <linux/init.h>
  14#include <linux/gfp.h>
  15#include <linux/usb.h>
  16#include <linux/netdevice.h>
  17#include <linux/bitrev.h>
  18#include "st5481.h"
  19
  20static inline void B_L1L2(struct st5481_bcs *bcs, int pr, void *arg)
  21{
  22        struct hisax_if *ifc = (struct hisax_if *) &bcs->b_if;
  23
  24        ifc->l1l2(ifc, pr, arg);
  25}
  26
  27/*
  28 * Encode and transmit next frame.
  29 */
  30static void usb_b_out(struct st5481_bcs *bcs, int buf_nr)
  31{
  32        struct st5481_b_out *b_out = &bcs->b_out;
  33        struct st5481_adapter *adapter = bcs->adapter;
  34        struct urb *urb;
  35        unsigned int packet_size, offset;
  36        int len, buf_size, bytes_sent;
  37        int i;
  38        struct sk_buff *skb;
  39
  40        if (test_and_set_bit(buf_nr, &b_out->busy)) {
  41                DBG(4, "ep %d urb %d busy", (bcs->channel + 1) * 2, buf_nr);
  42                return;
  43        }
  44        urb = b_out->urb[buf_nr];
  45
  46        // Adjust isoc buffer size according to flow state
  47        if (b_out->flow_event & (OUT_DOWN | OUT_UNDERRUN)) {
  48                buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST;
  49                packet_size = SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST;
  50                DBG(4, "B%d,adjust flow,add %d bytes", bcs->channel + 1, B_FLOW_ADJUST);
  51        } else if (b_out->flow_event & OUT_UP) {
  52                buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST;
  53                packet_size = SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST;
  54                DBG(4, "B%d,adjust flow,remove %d bytes", bcs->channel + 1, B_FLOW_ADJUST);
  55        } else {
  56                buf_size = NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT;
  57                packet_size = 8;
  58        }
  59        b_out->flow_event = 0;
  60
  61        len = 0;
  62        while (len < buf_size) {
  63                if ((skb = b_out->tx_skb)) {
  64                        DBG_SKB(0x100, skb);
  65                        DBG(4, "B%d,len=%d", bcs->channel + 1, skb->len);
  66
  67                        if (bcs->mode == L1_MODE_TRANS) {
  68                                bytes_sent = buf_size - len;
  69                                if (skb->len < bytes_sent)
  70                                        bytes_sent = skb->len;
  71                                {       /* swap tx bytes to get hearable audio data */
  72                                        register unsigned char *src  = skb->data;
  73                                        register unsigned char *dest = urb->transfer_buffer + len;
  74                                        register unsigned int count;
  75                                        for (count = 0; count < bytes_sent; count++)
  76                                                *dest++ = bitrev8(*src++);
  77                                }
  78                                len += bytes_sent;
  79                        } else {
  80                                len += isdnhdlc_encode(&b_out->hdlc_state,
  81                                                       skb->data, skb->len, &bytes_sent,
  82                                                       urb->transfer_buffer + len, buf_size-len);
  83                        }
  84
  85                        skb_pull(skb, bytes_sent);
  86
  87                        if (!skb->len) {
  88                                // Frame sent
  89                                b_out->tx_skb = NULL;
  90                                B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long) skb->truesize);
  91                                dev_kfree_skb_any(skb);
  92
  93/*                              if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
  94/*                                      st5481B_sched_event(bcs, B_XMTBUFREADY); */
  95/*                              } */
  96                        }
  97                } else {
  98                        if (bcs->mode == L1_MODE_TRANS) {
  99                                memset(urb->transfer_buffer + len, 0xff, buf_size-len);
 100                                len = buf_size;
 101                        } else {
 102                                // Send flags
 103                                len += isdnhdlc_encode(&b_out->hdlc_state,
 104                                                       NULL, 0, &bytes_sent,
 105                                                       urb->transfer_buffer + len, buf_size-len);
 106                        }
 107                }
 108        }
 109
 110        // Prepare the URB
 111        for (i = 0, offset = 0; offset < len; i++) {
 112                urb->iso_frame_desc[i].offset = offset;
 113                urb->iso_frame_desc[i].length = packet_size;
 114                offset += packet_size;
 115                packet_size = SIZE_ISO_PACKETS_B_OUT;
 116        }
 117        urb->transfer_buffer_length = len;
 118        urb->number_of_packets = i;
 119        urb->dev = adapter->usb_dev;
 120
 121        DBG_ISO_PACKET(0x200, urb);
 122
 123        SUBMIT_URB(urb, GFP_NOIO);
 124}
 125
 126/*
 127 * Start transferring (flags or data) on the B channel, since
 128 * FIFO counters has been set to a non-zero value.
 129 */
 130static void st5481B_start_xfer(void *context)
 131{
 132        struct st5481_bcs *bcs = context;
 133
 134        DBG(4, "B%d", bcs->channel + 1);
 135
 136        // Start transmitting (flags or data) on B channel
 137
 138        usb_b_out(bcs, 0);
 139        usb_b_out(bcs, 1);
 140}
 141
 142/*
 143 * If the adapter has only 2 LEDs, the green
 144 * LED will blink with a rate depending
 145 * on the number of channels opened.
 146 */
 147static void led_blink(struct st5481_adapter *adapter)
 148{
 149        u_char leds = adapter->leds;
 150
 151        // 50 frames/sec for each channel
 152        if (++adapter->led_counter % 50) {
 153                return;
 154        }
 155
 156        if (adapter->led_counter % 100) {
 157                leds |= GREEN_LED;
 158        } else {
 159                leds &= ~GREEN_LED;
 160        }
 161
 162        st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, leds, NULL, NULL);
 163}
 164
 165static void usb_b_out_complete(struct urb *urb)
 166{
 167        struct st5481_bcs *bcs = urb->context;
 168        struct st5481_b_out *b_out = &bcs->b_out;
 169        struct st5481_adapter *adapter = bcs->adapter;
 170        int buf_nr;
 171
 172        buf_nr = get_buf_nr(b_out->urb, urb);
 173        test_and_clear_bit(buf_nr, &b_out->busy);
 174
 175        if (unlikely(urb->status < 0)) {
 176                switch (urb->status) {
 177                case -ENOENT:
 178                case -ESHUTDOWN:
 179                case -ECONNRESET:
 180                        DBG(4, "urb killed status %d", urb->status);
 181                        return; // Give up
 182                default:
 183                        WARNING("urb status %d", urb->status);
 184                        if (b_out->busy == 0) {
 185                                st5481_usb_pipe_reset(adapter, (bcs->channel + 1) * 2 | USB_DIR_OUT, NULL, NULL);
 186                        }
 187                        break;
 188                }
 189        }
 190
 191        usb_b_out(bcs, buf_nr);
 192
 193        if (adapter->number_of_leds == 2)
 194                led_blink(adapter);
 195}
 196
 197/*
 198 * Start or stop the transfer on the B channel.
 199 */
 200static void st5481B_mode(struct st5481_bcs *bcs, int mode)
 201{
 202        struct st5481_b_out *b_out = &bcs->b_out;
 203        struct st5481_adapter *adapter = bcs->adapter;
 204
 205        DBG(4, "B%d,mode=%d", bcs->channel + 1, mode);
 206
 207        if (bcs->mode == mode)
 208                return;
 209
 210        bcs->mode = mode;
 211
 212        // Cancel all USB transfers on this B channel
 213        usb_unlink_urb(b_out->urb[0]);
 214        usb_unlink_urb(b_out->urb[1]);
 215        b_out->busy = 0;
 216
 217        st5481_in_mode(&bcs->b_in, mode);
 218        if (bcs->mode != L1_MODE_NULL) {
 219                // Open the B channel
 220                if (bcs->mode != L1_MODE_TRANS) {
 221                        u32 features = HDLC_BITREVERSE;
 222                        if (bcs->mode == L1_MODE_HDLC_56K)
 223                                features |= HDLC_56KBIT;
 224                        isdnhdlc_out_init(&b_out->hdlc_state, features);
 225                }
 226                st5481_usb_pipe_reset(adapter, (bcs->channel + 1) * 2, NULL, NULL);
 227
 228                // Enable B channel interrupts
 229                st5481_usb_device_ctrl_msg(adapter, FFMSK_B1 + (bcs->channel * 2),
 230                                           OUT_UP + OUT_DOWN + OUT_UNDERRUN, NULL, NULL);
 231
 232                // Enable B channel FIFOs
 233                st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel * 2), 32, st5481B_start_xfer, bcs);
 234                if (adapter->number_of_leds == 4) {
 235                        if (bcs->channel == 0) {
 236                                adapter->leds |= B1_LED;
 237                        } else {
 238                                adapter->leds |= B2_LED;
 239                        }
 240                }
 241        } else {
 242                // Disable B channel interrupts
 243                st5481_usb_device_ctrl_msg(adapter, FFMSK_B1+(bcs->channel * 2), 0, NULL, NULL);
 244
 245                // Disable B channel FIFOs
 246                st5481_usb_device_ctrl_msg(adapter, OUT_B1_COUNTER+(bcs->channel * 2), 0, NULL, NULL);
 247
 248                if (adapter->number_of_leds == 4) {
 249                        if (bcs->channel == 0) {
 250                                adapter->leds &= ~B1_LED;
 251                        } else {
 252                                adapter->leds &= ~B2_LED;
 253                        }
 254                } else {
 255                        st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, adapter->leds, NULL, NULL);
 256                }
 257                if (b_out->tx_skb) {
 258                        dev_kfree_skb_any(b_out->tx_skb);
 259                        b_out->tx_skb = NULL;
 260                }
 261
 262        }
 263}
 264
 265static int st5481_setup_b_out(struct st5481_bcs *bcs)
 266{
 267        struct usb_device *dev = bcs->adapter->usb_dev;
 268        struct usb_interface *intf;
 269        struct usb_host_interface *altsetting = NULL;
 270        struct usb_host_endpoint *endpoint;
 271        struct st5481_b_out *b_out = &bcs->b_out;
 272
 273        DBG(4, "");
 274
 275        intf = usb_ifnum_to_if(dev, 0);
 276        if (intf)
 277                altsetting = usb_altnum_to_altsetting(intf, 3);
 278        if (!altsetting)
 279                return -ENXIO;
 280
 281        // Allocate URBs and buffers for the B channel out
 282        endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2];
 283
 284        DBG(4, "endpoint address=%02x,packet size=%d",
 285            endpoint->desc.bEndpointAddress, le16_to_cpu(endpoint->desc.wMaxPacketSize));
 286
 287        // Allocate memory for 8000bytes/sec + extra bytes if underrun
 288        return st5481_setup_isocpipes(b_out->urb, dev,
 289                                      usb_sndisocpipe(dev, endpoint->desc.bEndpointAddress),
 290                                      NUM_ISO_PACKETS_B, SIZE_ISO_PACKETS_B_OUT,
 291                                      NUM_ISO_PACKETS_B * SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST,
 292                                      usb_b_out_complete, bcs);
 293}
 294
 295static void st5481_release_b_out(struct st5481_bcs *bcs)
 296{
 297        struct st5481_b_out *b_out = &bcs->b_out;
 298
 299        DBG(4, "");
 300
 301        st5481_release_isocpipes(b_out->urb);
 302}
 303
 304int st5481_setup_b(struct st5481_bcs *bcs)
 305{
 306        int retval;
 307
 308        DBG(4, "");
 309
 310        retval = st5481_setup_b_out(bcs);
 311        if (retval)
 312                goto err;
 313        bcs->b_in.bufsize = HSCX_BUFMAX;
 314        bcs->b_in.num_packets = NUM_ISO_PACKETS_B;
 315        bcs->b_in.packet_size = SIZE_ISO_PACKETS_B_IN;
 316        bcs->b_in.ep = (bcs->channel ? EP_B2_IN : EP_B1_IN) | USB_DIR_IN;
 317        bcs->b_in.counter = bcs->channel ? IN_B2_COUNTER : IN_B1_COUNTER;
 318        bcs->b_in.adapter = bcs->adapter;
 319        bcs->b_in.hisax_if = &bcs->b_if.ifc;
 320        retval = st5481_setup_in(&bcs->b_in);
 321        if (retval)
 322                goto err_b_out;
 323
 324
 325        return 0;
 326
 327err_b_out:
 328        st5481_release_b_out(bcs);
 329err:
 330        return retval;
 331}
 332
 333/*
 334 * Release buffers and URBs for the B channels
 335 */
 336void st5481_release_b(struct st5481_bcs *bcs)
 337{
 338        DBG(4, "");
 339
 340        st5481_release_in(&bcs->b_in);
 341        st5481_release_b_out(bcs);
 342}
 343
 344/*
 345 * st5481_b_l2l1 is the entry point for upper layer routines that want to
 346 * transmit on the B channel.  PH_DATA | REQUEST is a normal packet that
 347 * we either start transmitting (if idle) or queue (if busy).
 348 * PH_PULL | REQUEST can be called to request a callback message
 349 * (PH_PULL | CONFIRM)
 350 * once the link is idle.  After a "pull" callback, the upper layer
 351 * routines can use PH_PULL | INDICATION to send data.
 352 */
 353void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
 354{
 355        struct st5481_bcs *bcs = ifc->priv;
 356        struct sk_buff *skb = arg;
 357        long mode;
 358
 359        DBG(4, "");
 360
 361        switch (pr) {
 362        case PH_DATA | REQUEST:
 363                BUG_ON(bcs->b_out.tx_skb);
 364                bcs->b_out.tx_skb = skb;
 365                break;
 366        case PH_ACTIVATE | REQUEST:
 367                mode = (long) arg;
 368                DBG(4, "B%d,PH_ACTIVATE_REQUEST %ld", bcs->channel + 1, mode);
 369                st5481B_mode(bcs, mode);
 370                B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
 371                break;
 372        case PH_DEACTIVATE | REQUEST:
 373                DBG(4, "B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1);
 374                st5481B_mode(bcs, L1_MODE_NULL);
 375                B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL);
 376                break;
 377        default:
 378                WARNING("pr %#x\n", pr);
 379        }
 380}
 381