Exemplo n.º 1
0
/*
 * 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;
}
Exemplo n.º 2
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;
}