/* This is our function to emulate usb_control_msg() but give us enough * access to make aborts/resets work */ int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size) { int status; struct usb_ctrlrequest *dr; /* allocate the device request structure */ dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO); if (!dr) return -ENOMEM; /* fill in the structure */ dr->bRequestType = requesttype; dr->bRequest = request; dr->wValue = cpu_to_le16(value); dr->wIndex = cpu_to_le16(index); dr->wLength = cpu_to_le16(size); /* set up data structures for the wakeup system */ init_completion(&us->current_done); /* lock the URB */ down(&(us->current_urb_sem)); /* fill the URB */ FILL_CONTROL_URB(us->current_urb, us->pusb_dev, pipe, (unsigned char*) dr, data, size, usb_stor_blocking_completion, &us->current_done); us->current_urb->actual_length = 0; us->current_urb->error_count = 0; us->current_urb->transfer_flags = USB_ASYNC_UNLINK; us->current_urb->status = 0; /* submit the URB */ status = usb_submit_urb(us->current_urb); if (status) { /* something went wrong */ up(&(us->current_urb_sem)); kfree(dr); return status; } /* wait for the completion of the URB */ up(&(us->current_urb_sem)); wait_for_completion(&us->current_done); down(&(us->current_urb_sem)); /* return the actual length of the data transferred if no error*/ status = us->current_urb->status; if (status == -ENOENT) status = -ECONNRESET; if (status >= 0) status = us->current_urb->actual_length; /* release the lock and return status */ up(&(us->current_urb_sem)); kfree(dr); return status; }
/* * This is our function to emulate USBH_SendCtrlMsg() but give us enough * access to make aborts/resets work */ static int usb_stor_control_msg(UMAS_DATA_T *umas, uint32_t pipe, uint8_t request, uint8_t requesttype, uint16_t value, uint16_t index, void *data, uint16_t size) { URB_T *urb = umas->current_urb; int status; volatile int t0; DEV_REQ_T dr; /* fill in the structure */ dr.requesttype = requesttype; dr.request = request; dr.value = value; dr.index = index; dr.length = size; /* fill the URB */ FILL_CONTROL_URB(urb, umas->pusb_dev, pipe, (uint8_t *)&dr, data, size, usb_stor_blocking_completion, NULL); urb->actual_length = 0; urb->error_count = 0; urb->transfer_flags = USB_ASYNC_UNLINK; _UmasUrbComplete = 0; /* submit the URB */ status = USBH_SubmitUrb(urb); if(status) return status; /* wait for the completion of the URB */ #if 1 for(t0 = 0; t0 < 0x8000000; t0++) { if(is_urb_completed()) break; } if(t0 >= 0x8000000) #else t0 = umas_get_ticks(); while(umas_get_ticks() - t0 < 300) { if(is_urb_completed()) break; } if(umas_get_ticks() - t0 >= 300) #endif { UMAS_DEBUG("usb_stor_control_msg time-out failed!\n"); return USB_ERR_TIMEOUT; } /* return the actual length of the data transferred if no error*/ status = urb->status; if(status >= 0) status = urb->actual_length; return status; }
static int hci_usb_ctrl_msg(struct hci_usb *husb, struct sk_buff *skb) { struct urb *urb = husb->ctrl_urb; devrequest *dr = &husb->dev_req; int pipe, status; DBG("%s len %d", husb->hdev.name, skb->len); pipe = usb_sndctrlpipe(husb->udev, 0); dr->requesttype = HCI_CTRL_REQ; dr->request = 0; dr->index = 0; dr->value = 0; dr->length = cpu_to_le16(skb->len); FILL_CONTROL_URB(urb, husb->udev, pipe, (void*)dr, skb->data, skb->len, hci_usb_ctrl, skb); if ((status = usb_submit_urb(urb))) { DBG("%s control URB submit failed %d", husb->hdev.name, status); return status; } return 0; }
/* Completion handler for dummy retry packet */ static void auerswald_ctrlread_wretcomplete(struct urb *urb) { struct auerbuf *bp = (struct auerbuf *) urb->context; struct auerswald *cp; int ret; dbg("auerswald_ctrlread_wretcomplete called"); dbg("complete with status: %d", urb->status); cp = ((struct auerswald *) ((char *) (bp->list) - (unsigned long) (&((struct auerswald *) 0)-> bufctl))); /* check if it is possible to advance */ if (!auerswald_status_retry(urb->status) || !cp->usbdev) { /* reuse the buffer */ err("control dummy: transmission error %d, can not retry", urb->status); auerbuf_releasebuf(bp); /* Wake up all processes waiting for a buffer */ wake_up(&cp->bufferwait); return; } /* fill the control message */ bp->dr->bRequestType = AUT_RREQ; bp->dr->bRequest = AUV_RBLOCK; bp->dr->wLength = bp->dr->wValue; /* temporary stored */ bp->dr->wValue = cpu_to_le16(1); /* Retry Flag */ /* bp->dr->wIndex = channel id; remains */ FILL_CONTROL_URB(bp->urbp, cp->usbdev, usb_rcvctrlpipe(cp->usbdev, 0), (unsigned char *) bp->dr, bp->bufp, le16_to_cpu(bp->dr->wLength), (usb_complete_t) auerswald_ctrlread_complete, bp); /* submit the control msg as next paket */ ret = auerchain_submit_urb_list(&cp->controlchain, bp->urbp, 1); if (ret) { dbg("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret); bp->urbp->status = ret; auerswald_ctrlread_complete(bp->urbp); } }
static void ecos_usbeth_set_rx_mode(struct net_device* net) { ecos_usbeth* usbeth = (ecos_usbeth*) net->priv; __u16 promiscuous = net->flags & IFF_PROMISC; int res; if (promiscuous != usbeth->target_promiscuous) { devrequest* req; urb_t* urb; urb = usb_alloc_urb(0); if ((urb_t*)0 == urb) { return; } req = kmalloc(sizeof(devrequest), GFP_KERNEL); if ((devrequest*)0 == req) { usb_free_urb(urb); return; } req->requesttype = USB_TYPE_CLASS | USB_RECIP_DEVICE; req->request = ECOS_USBETH_CONTROL_SET_PROMISCUOUS_MODE; req->value = cpu_to_le16p(&promiscuous); req->index = 0; req->length = 0; FILL_CONTROL_URB(urb, usbeth->usb_dev, usb_sndctrlpipe(usbeth->usb_dev, 0), (unsigned char*) req, (void*) 0, 0, &ecos_usbeth_set_rx_mode_callback, (void*) usbeth); res = usb_submit_urb(urb); if (0 != res) { kfree(req); usb_free_urb(urb); } else { usbeth->target_promiscuous = promiscuous; } } }
/* Open the D-channel once more */ static void auerisdn_dcopen(unsigned long data) { struct auerswald *cp = (struct auerswald *) data; struct auerbuf *bp; int ret; if (cp->disconnecting) return; dbg("auerisdn_dcopen running"); /* get a buffer for the command */ bp = auerbuf_getbuf(&cp->bufctl); /* if no buffer available: can't change the mode */ if (!bp) { err("auerisdn_dcopen: no data buffer available"); return; } /* fill the control message */ bp->dr->bRequestType = AUT_WREQ; bp->dr->bRequest = AUV_CHANNELCTL; bp->dr->wValue = cpu_to_le16(1); bp->dr->wIndex = cpu_to_le16(0); bp->dr->wLength = cpu_to_le16(0); FILL_CONTROL_URB(bp->urbp, cp->usbdev, usb_sndctrlpipe(cp->usbdev, 0), (unsigned char *) bp->dr, bp->bufp, 0, (usb_complete_t) auerisdn_dcopen_complete, bp); /* submit the control msg */ ret = auerchain_submit_urb(&cp->controlchain, bp->urbp); dbg("dcopen submitted"); if (ret) { bp->urbp->status = ret; auerisdn_dcopen_complete(bp->urbp); } return; }
static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size) { int ret; if (test_bit(RX_REG_SET, &dev->flags)) return -EAGAIN; dev->dr.bRequestType = RTL8150_REQT_WRITE; dev->dr.bRequest = RTL8150_REQ_SET_REGS; dev->dr.wValue = cpu_to_le16(indx); dev->dr.wIndex = 0; dev->dr.wLength = cpu_to_le16(2); dev->ctrl_urb->transfer_buffer_length = 2; FILL_CONTROL_URB(dev->ctrl_urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr, &dev->rx_creg, 2, ctrl_callback, dev); if ((ret = usb_submit_urb(dev->ctrl_urb))) err("control request submission failed: %d", ret); else set_bit(RX_REG_SET, &dev->flags); return ret; }
/* Decide if we need to issue a control message and do so. Must be called with pm->lock down */ static void powermate_sync_state(struct powermate_device *pm) { if(pm->requires_update == 0) return; /* no updates are required */ if(pm->config.status == -EINPROGRESS) return; /* an update is already in progress; it'll issue this update when it completes */ if(pm->requires_update & UPDATE_PULSE_ASLEEP){ pm->configdr.wValue = cpu_to_le16( SET_PULSE_ASLEEP ); pm->configdr.wIndex = cpu_to_le16( pm->pulse_asleep ? 1 : 0 ); pm->requires_update &= ~UPDATE_PULSE_ASLEEP; }else if(pm->requires_update & UPDATE_PULSE_AWAKE){ pm->configdr.wValue = cpu_to_le16( SET_PULSE_AWAKE ); pm->configdr.wIndex = cpu_to_le16( pm->pulse_awake ? 1 : 0 ); pm->requires_update &= ~UPDATE_PULSE_AWAKE; }else if(pm->requires_update & UPDATE_PULSE_MODE){ int op, arg; /* the powermate takes an operation and an argument for its pulse algorithm. the operation can be: 0: divide the speed 1: pulse at normal speed 2: multiply the speed the argument only has an effect for operations 0 and 2, and ranges between 1 (least effect) to 255 (maximum effect). thus, several states are equivalent and are coalesced into one state. we map this onto a range from 0 to 510, with: 0 -- 254 -- use divide (0 = slowest) 255 -- use normal speed 256 -- 510 -- use multiple (510 = fastest). Only values of 'arg' quite close to 255 are particularly useful/spectacular. */ if(pm->pulse_speed < 255){ op = 0; // divide arg = 255 - pm->pulse_speed; }else if(pm->pulse_speed > 255){ op = 2; // multiply arg = pm->pulse_speed - 255; }else{ op = 1; // normal speed arg = 0; // can be any value } pm->configdr.wValue = cpu_to_le16( (pm->pulse_table << 8) | SET_PULSE_MODE ); pm->configdr.wIndex = cpu_to_le16( (arg << 8) | op ); pm->requires_update &= ~UPDATE_PULSE_MODE; }else if(pm->requires_update & UPDATE_STATIC_BRIGHTNESS){ pm->configdr.wValue = cpu_to_le16( SET_STATIC_BRIGHTNESS ); pm->configdr.wIndex = cpu_to_le16( pm->static_brightness ); pm->requires_update &= ~UPDATE_STATIC_BRIGHTNESS; }else{ printk(KERN_ERR "powermate: unknown update required"); pm->requires_update = 0; /* fudge the bug */ return; } pm->config.dev = pm->udev; /* is this necessary? */ pm->configdr.bRequestType = 0x41; /* vendor request */ pm->configdr.bRequest = 0x01; pm->configdr.wLength = 0; FILL_CONTROL_URB(&pm->config, pm->udev, usb_sndctrlpipe(pm->udev, 0), (void*)&pm->configdr, 0, 0, powermate_config_complete, pm); if(usb_submit_urb(&pm->config)) printk(KERN_ERR "powermate: usb_submit_urb(config) failed"); }
int __devinit st5481_setup_usb(struct st5481_adapter *adapter) { struct usb_device *dev = adapter->usb_dev; struct st5481_ctrl *ctrl = &adapter->ctrl; struct st5481_intr *intr = &adapter->intr; struct usb_interface_descriptor *altsetting; struct usb_endpoint_descriptor *endpoint; int status; urb_t *urb; u_char *buf; DBG(1,""); if ((status = usb_set_configuration (dev,dev->config[0].bConfigurationValue)) < 0) { WARN("set_configuration failed,status=%d",status); return status; } altsetting = &(dev->config->interface[0].altsetting[3]); // Check if the config is sane if ( altsetting->bNumEndpoints != 7 ) { WARN("expecting 7 got %d endpoints!", altsetting->bNumEndpoints); return -EINVAL; } // The descriptor is wrong for some early samples of the ST5481 chip altsetting->endpoint[3].wMaxPacketSize = 32; altsetting->endpoint[4].wMaxPacketSize = 32; // Use alternative setting 3 on interface 0 to have 2B+D if ((status = usb_set_interface (dev, 0, 3)) < 0) { WARN("usb_set_interface failed,status=%d",status); return status; } // Allocate URB for control endpoint urb = usb_alloc_urb(0); if (!urb) { return -ENOMEM; } ctrl->urb = urb; // Fill the control URB FILL_CONTROL_URB (urb, dev, usb_sndctrlpipe(dev, 0), NULL, NULL, 0, usb_ctrl_complete, adapter); fifo_init(&ctrl->msg_fifo.f, ARRAY_SIZE(ctrl->msg_fifo.data)); // Allocate URBs and buffers for interrupt endpoint urb = usb_alloc_urb(0); if (!urb) { return -ENOMEM; } intr->urb = urb; buf = kmalloc(INT_PKT_SIZE, GFP_KERNEL); if (!buf) { return -ENOMEM; } endpoint = &altsetting->endpoint[EP_INT-1]; // Fill the interrupt URB FILL_INT_URB(urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), buf, INT_PKT_SIZE, usb_int_complete, adapter, endpoint->bInterval); return 0; }
/* D-channel transfer function L2->L1 */ static void auerisdn_d_l2l1(struct hisax_if *hisax_d_if, int pr, void *arg) { struct auerhisax *ahp; struct sk_buff *skb; unsigned int len; int ret; struct auerbuf *bp; struct auerswald *cp; unsigned long flags; unsigned int l2_index; unsigned char c; unsigned char l2_header[32]; unsigned char *sp; dbg("hisax D-Channel l2l1 called"); /* Get reference to auerhisax struct */ cp = NULL; ahp = hisax_d_if->priv; if (ahp) cp = ahp->cp; if (cp && !cp->disconnecting) { /* normal usage */ switch (pr) { case PH_ACTIVATE | REQUEST: /* activation request */ dbg("Activation Request"); cp->isdn.dc_activated = 1; /* send activation back to layer 2 */ auerisdn_d_l1l2(&cp->isdn, PH_ACTIVATE | INDICATION, NULL); break; case PH_DEACTIVATE | REQUEST: /* deactivation request */ dbg("Deactivation Request"); cp->isdn.dc_activated = 0; /* send deactivation back to layer 2 */ auerisdn_d_l1l2(&cp->isdn, PH_DEACTIVATE | INDICATION, NULL); break; case PH_DATA | REQUEST: /* Transmit data request */ skb = (struct sk_buff *) arg; len = skb->len; l2_index = 0; sp = skb->data; dump("Data Request:", sp, len); /* Parse the L2 header */ if (!len) goto phd_free; c = *sp++; /* SAPI */ l2_header[l2_index++] = c; len--; if (!len) goto phd_free; c = *sp++; /* TEI */ l2_header[l2_index++] = c; len--; if (!len) goto phd_free; c = *sp++; /* Control Field, Byte 1 */ len--; if (!(c & 0x01)) { /* I FRAME */ dbg("I Frame"); if (!len) goto phd_free; spin_lock_irqsave(&ahp->seq_lock, flags); ahp->rxseq = c + 2; /* store new sequence info */ spin_unlock_irqrestore(&ahp->seq_lock, flags); sp++; /* skip Control Field, Byte 2 */ len--; /* Check for RELEASE command */ /* and change to RELEASE_COMPLETE */ if (sp[3] == 0x4D) sp[3] = 0x5A; goto phd_send; } /* check the frame type */ switch (c) { case 0x03: /* UI frame */ dbg("UI Frame"); if (l2_header[0] == 0xFC) { dbg("TEI Managment"); l2_header[0] = 0xFE; /* set C/R bit in answer */ l2_header[l2_index++] = c; /* Answer is UI frame */ if (!len) break; c = *sp++; /* Managment ID */ len--; if (c != 0x0F) break; l2_header[l2_index++] = c; /* Read Reference Number */ if (!len) break; l2_header[l2_index++] = *sp++; len--; if (!len) break; l2_header[l2_index++] = *sp++; len--; if (!len) break; c = *sp++; /* Message Type */ len--; switch (c) { case 0x01: /* Identity Request */ dbg("Identity Request"); l2_header[l2_index++] = 0x02; /* Identity Assign */ l2_header[l2_index++] = (AUISDN_TEI << 1) | 0x01; goto phd_answer; default: dbg("Unhandled TEI Managment %X", (int) c); break; } // throw away goto phd_free; } /* else send UI frame out */ goto phd_send; case 0x01: /* RR frame */ case 0x05: /* RNR frame */ dbg("RR/RNR Frame"); if (!len) break; c = *sp++; /* Control Field, Byte 2 */ len--; if (!(c & 0x01)) break; /* P/F = 1 in commands */ if (l2_header[0] & 0x02) break; /* C/R = 0 from TE */ dbg("Send RR as answer"); l2_header[l2_index++] = 0x01; /* send an RR as Answer */ spin_lock_irqsave(&ahp->seq_lock, flags); l2_header[l2_index++] = ahp->rxseq | 0x01; spin_unlock_irqrestore(&ahp->seq_lock, flags); goto phd_answer; case 0x7F: /* SABME */ dbg("SABME"); spin_lock_irqsave(&ahp->seq_lock, flags); ahp->txseq = 0; ahp->rxseq = 0; spin_unlock_irqrestore(&ahp->seq_lock, flags); l2_header[l2_index++] = 0x73; /* UA */ goto phd_answer; case 0x53: /* DISC */ dbg("DISC"); /* Send back a UA */ l2_header[l2_index++] = 0x73; /* UA */ goto phd_answer; default: dbg("Unhandled L2 Message %X", (int) c); break; } /* all done */ goto phd_free; /* we have to generate a local answer */ /* first, confirm old message, free old skb */ phd_answer:auerisdn_d_confirmskb(cp, skb); /* allocate a new skbuff */ skb = dev_alloc_skb(l2_index); if (!skb) { err("no memory for new skb"); break; } dump("local answer to L2 is:", l2_header, l2_index); memcpy(skb_put(skb, l2_index), l2_header, l2_index); auerisdn_d_l1l2(&cp->isdn, PH_DATA | INDICATION, skb); break; /* we have to send the L3 message out */ phd_send:if (!len) goto phd_free; /* no message left */ /* get a new data buffer */ bp = auerbuf_getbuf(&cp->bufctl); if (!bp) { warn("no auerbuf free"); goto phd_free; } /* protect against too big write requests */ /* Should not happen */ if (len > cp->maxControlLength) { err("too long D-channel paket truncated"); len = cp->maxControlLength; } /* Copy the data */ memcpy(bp->bufp + AUH_SIZE, sp, len); /* set the header byte */ *(bp->bufp) = cp->isdn.dchannelservice. id | AUH_DIRECT | AUH_UNSPLIT; /* Set the transfer Parameters */ bp->len = len + AUH_SIZE; bp->dr->bRequestType = AUT_WREQ; bp->dr->bRequest = AUV_WBLOCK; bp->dr->wValue = cpu_to_le16(0); bp->dr->wIndex = cpu_to_le16(cp->isdn.dchannelservice. id | AUH_DIRECT | AUH_UNSPLIT); bp->dr->wLength = cpu_to_le16(len + AUH_SIZE); FILL_CONTROL_URB(bp->urbp, cp->usbdev, usb_sndctrlpipe(cp->usbdev, 0), (unsigned char *) bp->dr, bp->bufp, len + AUH_SIZE, auerisdn_dcw_complete, bp); /* up we go */ ret = auerchain_submit_urb(&cp->controlchain, bp->urbp); if (ret) auerisdn_dcw_complete(bp->urbp); else dbg("auerisdn_dwrite: Write OK"); /* confirm message, free skb */ phd_free:auerisdn_d_confirmskb(cp, skb); break; default: warn("pr %#x\n", pr); break; } } else { /* hisax interface is down */ switch (pr) { case PH_ACTIVATE | REQUEST: /* activation request */ dbg("D channel PH_ACTIVATE | REQUEST with interface down"); /* don't answer this request! Endless... */ break; case PH_DEACTIVATE | REQUEST: /* deactivation request */ dbg("D channel PH_DEACTIVATE | REQUEST with interface down"); hisax_d_if->l1l2(hisax_d_if, PH_DEACTIVATE | INDICATION, NULL); break; case PH_DATA | REQUEST: /* Transmit data request */ dbg("D channel PH_DATA | REQUEST with interface down"); skb = (struct sk_buff *) arg; /* free data buffer */ if (skb) { skb_pull(skb, skb->len); dev_kfree_skb_any(skb); } /* send confirmation back to layer 2 */ hisax_d_if->l1l2(hisax_d_if, PH_DATA | CONFIRM, NULL); break; default: warn("pr %#x\n", pr); break; } } }
/* Translate non-ETSI ISDN messages from the device */ static void auerisdn_translate_incoming(struct auerswald *cp, unsigned char *msg, unsigned int len) { struct auerbuf *bp; int ret; /* Translate incomming CONNECT -> CONNECT_ACK */ /* Format: 0 1 2 3 4 5 6 7 */ /* SAPI TEI TXSEQ RXSEQ PID=08 CREFLEN=01 CREF MSG=7 ...*/ /* CREF.7 == 0 -> Incoming Call */ /* Check for minimum length */ if (len < 8) return; /* Check for a CONNECT, call originated from device */ if (((msg[6] & 0x80) == 0) && (msg[7] == 0x07)) { dbg("false CONNECT from device found"); /* change into CONNECT_ACK */ msg[7] = 0x0F; /* Send a CONNECT_ACK back to the device */ /* get a new data buffer */ bp = auerbuf_getbuf(&cp->bufctl); if (!bp) { warn("no auerbuf free"); return; } /* Form a CONNECT ACK */ bp->bufp[0] = cp->isdn.dchannelservice.id | AUH_DIRECT | AUH_UNSPLIT; bp->bufp[1] = 0x08; bp->bufp[2] = 0x01; bp->bufp[3] = msg[6] | 0x80; bp->bufp[4] = 0x0F; /* Set the transfer Parameters */ bp->len = 5; bp->dr->bRequestType = AUT_WREQ; bp->dr->bRequest = AUV_WBLOCK; bp->dr->wValue = cpu_to_le16(0); bp->dr->wIndex = cpu_to_le16(cp->isdn.dchannelservice. id | AUH_DIRECT | AUH_UNSPLIT); bp->dr->wLength = cpu_to_le16(5); FILL_CONTROL_URB(bp->urbp, cp->usbdev, usb_sndctrlpipe(cp->usbdev, 0), (unsigned char *) bp->dr, bp->bufp, 5, auerisdn_dcw_complete, bp); /* up we go */ ret = auerchain_submit_urb(&cp->controlchain, bp->urbp); if (ret) auerisdn_dcw_complete(bp->urbp); else dbg("auerisdn_translate: Write OK"); } /* Check for a DISCONNECT and change to RELEASE */ if (msg[7] == 0x45) { dbg("DISCONNECT changed to RELEASE"); msg[7] = 0x4D; return; } }
/* int completion handler. */ static void auerswald_int_complete(struct urb *urb) { unsigned int channelid; unsigned int bytecount; int ret; struct auerbuf *bp = NULL; struct auerswald *cp = (struct auerswald *) urb->context; dbg("auerswald_int_complete called"); /* do not respond to an error condition */ if (urb->status != 0) { dbg("nonzero URB status = %d", urb->status); return; } /* check if all needed data was received */ if (urb->actual_length < AU_IRQMINSIZE) { dbg("invalid data length received: %d bytes", urb->actual_length); return; } /* check the command code */ if (cp->intbufp[0] != AU_IRQCMDID) { dbg("invalid command received: %d", cp->intbufp[0]); return; } /* check the command type */ if (cp->intbufp[1] != AU_BLOCKRDY) { dbg("invalid command type received: %d", cp->intbufp[1]); return; } /* now extract the information */ channelid = cp->intbufp[2]; bytecount = le16_to_cpup(&cp->intbufp[3]); /* check the channel id */ if (channelid >= AUH_TYPESIZE) { dbg("invalid channel id received: %d", channelid); return; } /* check the byte count */ if (bytecount > (cp->maxControlLength + AUH_SIZE)) { dbg("invalid byte count received: %d", bytecount); return; } dbg("Service Channel = %d", channelid); dbg("Byte Count = %d", bytecount); /* get a buffer for the next data paket */ bp = auerbuf_getbuf(&cp->bufctl); /* if no buffer available: skip it */ if (!bp) { dbg("auerswald_int_complete: no data buffer available"); /* can we do something more? This is a big problem: if this int packet is ignored, the device will wait forever and not signal any more data. The only real solution is: having enought buffers! Or perhaps temporary disabling the int endpoint? */ return; } /* fill the control message */ bp->dr->bRequestType = AUT_RREQ; bp->dr->bRequest = AUV_RBLOCK; bp->dr->wValue = cpu_to_le16(0); bp->dr->wIndex = cpu_to_le16(channelid | AUH_DIRECT | AUH_UNSPLIT); bp->dr->wLength = cpu_to_le16(bytecount); FILL_CONTROL_URB(bp->urbp, cp->usbdev, usb_rcvctrlpipe(cp->usbdev, 0), (unsigned char *) bp->dr, bp->bufp, bytecount, (usb_complete_t) auerswald_ctrlread_complete, bp); /* submit the control msg */ ret = auerchain_submit_urb(&cp->controlchain, bp->urbp); if (ret) { dbg("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret); bp->urbp->status = ret; auerswald_ctrlread_complete(bp->urbp); /* here applies the same problem as above: device locking! */ } }
/* completion handler for receiving of control messages */ static void auerswald_ctrlread_complete(struct urb *urb) { unsigned int serviceid; struct auerswald *cp; struct auerscon *scp; struct auerbuf *bp = (struct auerbuf *) urb->context; int ret; dbg("auerswald_ctrlread_complete called"); cp = ((struct auerswald *) ((char *) (bp->list) - (unsigned long) (&((struct auerswald *) 0)-> bufctl))); /* check if there is valid data in this urb */ if (urb->status) { dbg("complete with non-zero status: %d", urb->status); /* should we do a retry? */ if (!auerswald_status_retry(urb->status) || !cp->usbdev || (cp->version < AUV_RETRY) || (bp->retries >= AU_RETRIES)) { /* reuse the buffer */ err("control read: transmission error %d, can not retry", urb->status); auerbuf_releasebuf(bp); /* Wake up all processes waiting for a buffer */ wake_up(&cp->bufferwait); return; } bp->retries++; dbg("Retry count = %d", bp->retries); /* send a long dummy control-write-message to allow device firmware to react */ bp->dr->bRequestType = AUT_WREQ; bp->dr->bRequest = AUV_DUMMY; bp->dr->wValue = bp->dr->wLength; /* temporary storage */ // bp->dr->wIndex channel ID remains bp->dr->wLength = cpu_to_le16(32); /* >= 8 bytes */ FILL_CONTROL_URB(bp->urbp, cp->usbdev, usb_sndctrlpipe(cp->usbdev, 0), (unsigned char *) bp->dr, bp->bufp, 32, (usb_complete_t) auerswald_ctrlread_wretcomplete, bp); /* submit the control msg as next paket */ ret = auerchain_submit_urb_list(&cp->controlchain, bp->urbp, 1); if (ret) { dbg("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret); bp->urbp->status = ret; auerswald_ctrlread_wretcomplete(bp->urbp); } return; } /* get the actual bytecount (incl. headerbyte) */ bp->len = urb->actual_length; serviceid = bp->bufp[0] & AUH_TYPEMASK; dbg("Paket with serviceid %d and %d bytes received", serviceid, bp->len); /* dispatch the paket */ scp = cp->services[serviceid]; if (scp) { /* look, Ma, a listener! */ scp->dispatch(scp, bp); } /* release the paket */ auerbuf_releasebuf(bp); /* Wake up all processes waiting for a buffer */ wake_up(&cp->bufferwait); }
/* Setup a B channel transfer mode */ static void auerisdn_bmode(struct auerisdnbc *bc, unsigned int mode) { struct auerswald *cp = bc->cp; struct auerbuf *bp; int ret; /* don't allow activation on disconnect */ if (cp->disconnecting) { mode = L1_MODE_NULL; /* Else check if something changed */ } else if (bc->mode != mode) { if ((mode != L1_MODE_NULL) && (mode != L1_MODE_TRANS)) { /* init RX hdlc decoder */ dbg("rcv init"); isdnhdlc_rcv_init(&bc->inp_hdlc_state, 0); /* init TX hdlc decoder */ dbg("out init"); isdnhdlc_out_init(&bc->outp_hdlc_state, 0, 0); } /* stop ASAP */ if (mode == L1_MODE_NULL) bc->mode = mode; if ((bc->mode == L1_MODE_NULL) || (mode == L1_MODE_NULL)) { /* Activation or deactivation required */ /* get a buffer for the command */ bp = auerbuf_getbuf(&cp->bufctl); /* if no buffer available: can't change the mode */ if (!bp) { err("auerisdn_bmode: no data buffer available"); return; } /* fill the control message */ bp->dr->bRequestType = AUT_WREQ; bp->dr->bRequest = AUV_CHANNELCTL; if (mode != L1_MODE_NULL) bp->dr->wValue = cpu_to_le16(1); else bp->dr->wValue = cpu_to_le16(0); bp->dr->wIndex = cpu_to_le16(AUH_B1CHANNEL + bc->channel); bp->dr->wLength = cpu_to_le16(0); *bp->bufp = mode; FILL_CONTROL_URB(bp->urbp, cp->usbdev, usb_sndctrlpipe(cp->usbdev, 0), (unsigned char *) bp->dr, bp->bufp, 0, (usb_complete_t) auerisdn_bmode_complete, bp); /* submit the control msg */ ret = auerchain_submit_urb(&cp->controlchain, bp->urbp); if (ret) { bp->urbp->status = ret; auerisdn_bmode_complete(bp->urbp); } return; } } /* new mode is set */ bc->mode = mode; /* send confirmation to L2 */ auerisdn_bconf(bc); }