diff --git a/drivers/isdn/hardware/mISDN/udevice.c b/drivers/isdn/hardware/mISDN/udevice.c index 48cbafc..5f5bbe7 100644 --- a/drivers/isdn/hardware/mISDN/udevice.c +++ b/drivers/isdn/hardware/mISDN/udevice.c @@ -138,6 +138,35 @@ p_pull_o(hisaxport_t *port, size_t count) } } +static size_t +next_frame_len(hisaxport_t *port) +{ + size_t len; + int *lp; + + if (port->cnt < IFRAME_HEAD_SIZE) { + int_errtxt("not a frameheader cnt(%d)", port->cnt); + return(0); + } + len = port->buf + port->size - port->op; + if (len < IFRAME_HEAD_SIZE) { + len = IFRAME_HEAD_SIZE - len - 4; + lp = (int *)(port->buf + len); + } else { + lp = (int *)(port->op + 12); + } + if (*lp <= 0) { + len = IFRAME_HEAD_SIZE; + } else { + len = IFRAME_HEAD_SIZE + *lp; + } + if (len < port->cnt) { + int_errtxt("size mismatch %d/%d", len, port->cnt); + return(0); + } + return(len); +} + static int hisax_rdata_raw(hisaxif_t *hif, struct sk_buff *skb) { hisaxdevice_t *dev; @@ -1218,6 +1247,34 @@ hisax_wdata_if(hisaxdevice_t *dev, iframe_t *iff, int len) { else hisax_rdata(dev, &off, 0); break; + case (MGR_SETDEVOPT | REQUEST): + used = head; + off.addr = iff->addr; + off.prim = MGR_SETDEVOPT | CONFIRM; + off.dinfo = 0; + off.len = 0; + if (iff->dinfo == FLG_HISAXPORT_ONEFRAME) { + test_and_set_bit(FLG_HISAXPORT_ONEFRAME, + &dev->rport.Flag); + } else if (!iff->dinfo) { + test_and_clear_bit(FLG_HISAXPORT_ONEFRAME, + &dev->rport.Flag); + } else { + off.len = -EINVAL; + } + hisax_rdata(dev, &off, 0); + break; + case (MGR_GETDEVOPT | REQUEST): + used = head; + off.addr = iff->addr; + off.prim = MGR_GETDEVOPT | CONFIRM; + off.len = 0; + if (test_bit(FLG_HISAXPORT_ONEFRAME, &dev->rport.Flag)) + off.dinfo = FLG_HISAXPORT_ONEFRAME; + else + off.dinfo = 0; + hisax_rdata(dev, &off, 0); + break; default: used = head + iff->len; if (lenrport.lock, flags); - if (count < dev->rport.cnt) - len = count; - else - len = dev->rport.cnt; + if (test_bit(FLG_HISAXPORT_ONEFRAME, &dev->rport.Flag)) { + len = next_frame_len(&dev->rport); + if (!len) { + spin_unlock_irqrestore(&dev->rport.lock, flags); + return(-EINVAL); + } + if (count < len) { + spin_unlock_irqrestore(&dev->rport.lock, flags); + return(-ENOSPC); + } + } else { + if (count < dev->rport.cnt) + len = count; + else + len = dev->rport.cnt; + } frag = dev->rport.buf + dev->rport.size - dev->rport.op; if (frag <= len) { if (copy_to_user(buf, dev->rport.op, frag)) {