/* * Read n bytes from the user memory and writes them into the board memory. * * card: the board * to: the destination address (in the board memory) * from: the source address (in the userspace memory) * n: number of bytes * * Return: 0 if OK, <0 if error. */ int copy_from_user_to_pam(tpam_card *card, void *to, const void *from, u32 n) { void *page; u32 count; /* allocate a free page for the data transfer */ if (!(page = (void *)__get_free_page(GFP_KERNEL))) { printk(KERN_ERR "TurboPAM(copy_from_user_to_pam): " "get_free_page failed\n"); return -ENOMEM; } while (n) { count = n < PAGE_SIZE ? n : PAGE_SIZE; /* copy data from the user memory into the kernel memory */ if (copy_from_user(page, from, count)) { /* this can fail... */ free_page((u32)page); return -EFAULT; } /* copy it from the kernel memory into the board memory */ spin_lock_irq(&card->lock); copy_to_pam(card, to, page, count); spin_unlock_irq(&card->lock); from += count; to += count; n -= count; } /* release allocated memory */ free_page((u32)page); return 0; }
/* * Try to send a packet from the board's send queue or from the channel's * send queue. * * card: the board. * channel: the channel (if NULL, the packet will be taken from the * board's send queue. If not, it will be taken from the * channel's send queue. * * Return: 0 if tpam_send_tq must try another card/channel combination * (meaning that no packet has been send), 1 if no more packets * can be send at that time (a packet has been send or the card is * still busy from a previous send). */ static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) { struct sk_buff *skb; u32 hpic; u32 downloadptr; skb_header *skbh; u32 waiting_too_long; dprintk("TurboPAM(tpam_sendpacket), card=%d, channel=%d\n", card->id, channel ? channel->num : -1); if (channel) { /* dequeue a packet from the channel's send queue */ if (!(skb = skb_dequeue(&channel->sendq))) { dprintk("TurboPAM(tpam_sendpacket): " "card=%d, channel=%d, no packet\n", card->id, channel->num); return 0; } /* if the channel is not ready to receive, requeue the packet * and return 0 to give a chance to another channel */ if (!channel->readytoreceive) { dprintk("TurboPAM(tpam_sendpacket): " "card=%d, channel=%d, channel not ready\n", card->id, channel->num); skb_queue_head(&channel->sendq, skb); return 0; } /* grab the board lock */ spin_lock_irq(&card->lock); /* if the board is busy, requeue the packet and return 1 since * there is no need to try another channel */ if (card->busy) { dprintk("TurboPAM(tpam_sendpacket): " "card=%d, channel=%d, card busy\n", card->id, channel->num); skb_queue_head(&channel->sendq, skb); spin_unlock_irq(&card->lock); return 1; } } else { /* dequeue a packet from the board's send queue */ if (!(skb = skb_dequeue(&card->sendq))) { dprintk("TurboPAM(tpam_sendpacket): " "card=%d, no packet\n", card->id); return 0; } /* grab the board lock */ spin_lock_irq(&card->lock); /* if the board is busy, requeue the packet and return 1 since * there is no need to try another channel */ if (card->busy) { dprintk("TurboPAM(tpam_sendpacket): " "card=%d, card busy\n", card->id); skb_queue_head(&card->sendq, skb); spin_unlock_irq(&card->lock); return 1; } } /* wait for the board to become ready */ waiting_too_long = 0; do { hpic = readl(card->bar0 + TPAM_HPIC_REGISTER); if (waiting_too_long++ > 0xfffffff) { spin_unlock_irq(&card->lock); printk(KERN_ERR "TurboPAM(tpam_sendpacket): " "waiting too long...\n"); return 1; } } while (hpic & 0x00000002); skbh = (skb_header *)skb->data; dprintk("TurboPAM(tpam_sendpacket): " "card=%d, card ready, sending %d/%d bytes\n", card->id, skbh->size, skbh->data_size); /* get the board's download pointer */ downloadptr = copy_from_pam_dword(card, (void *)TPAM_DOWNLOADPTR_REGISTER); /* copy the packet to the board at the downloadptr location */ copy_to_pam(card, (void *)downloadptr, skb->data + sizeof(skb_header), skbh->size); if (skbh->data_size) /* if there is some data in the packet, copy it too */ copy_to_pam(card, (void *)downloadptr + sizeof(pci_mpb) + 4096, skb->data + sizeof(skb_header) + skbh->size, skbh->data_size); /* card will become busy right now */ card->busy = 1; /* interrupt the board */ copy_to_pam_dword(card, (void *)TPAM_ACKDOWNLOAD_REGISTER, 0); readl(card->bar0 + TPAM_DSPINT_REGISTER); /* release the lock */ spin_unlock_irq(&card->lock); /* if a data ack was requested by the ISDN link layer, send it now */ if (skbh->ack) { isdn_ctrl ctrl; ctrl.driver = card->id; ctrl.command = ISDN_STAT_BSENT; ctrl.arg = channel->num; ctrl.parm.length = skbh->ack_size; (* card->interface.statcallb)(&ctrl); } /* free the sk_buff */ kfree_skb(skb); return 1; }