Пример #1
0
static void
bt3c_intr(void *context)
{
	bt3c_softc_p	sc = (bt3c_softc_p) context;
	u_int16_t	control, status;

	if (sc == NULL || sc->ith == NULL) {
		printf("%s: bogus interrupt\n", NG_BT3C_NODE_TYPE);
		return;
	}

	bt3c_read_control(sc, control);
	if ((control & 0x80) == 0)
		return;

	bt3c_read(sc, 0x7001, status);
	NG_BT3C_INFO(sc->dev, "control=%#x, status=%#x\n", control, status);

	if ((status & 0xff) == 0x7f || (status & 0xff) == 0xff) {
		NG_BT3C_WARN(sc->dev, "Strange status=%#x\n", status);
		return;
	}

	/* Receive complete */
	if (status & 0x0001)
		bt3c_receive(sc);

	/* Record status and schedule SWI */
	sc->status |= status;
	swi_sched(sc->ith, 0);

	/* Complete interrupt */
	bt3c_write(sc, 0x7001, 0x0000);
	bt3c_write_control(sc, control);
} /* bt3c_intr */
Пример #2
0
static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
{
	bt3c_info_t *info = dev_inst;
	unsigned int iobase;
	int iir;

	if (!info || !info->hdev) {
		BT_ERR("Call of irq %d for unknown device", irq);
		return IRQ_NONE;
	}

	iobase = info->link.io.BasePort1;

	spin_lock(&(info->lock));

	iir = inb(iobase + CONTROL);
	if (iir & 0x80) {
		int stat = bt3c_read(iobase, 0x7001);

		if ((stat & 0xff) == 0x7f) {
			BT_ERR("Very strange (stat=0x%04x)", stat);
		} else if ((stat & 0xff) != 0xff) {
			if (stat & 0x0020) {
				int stat = bt3c_read(iobase, 0x7002) & 0x10;
				BT_INFO("%s: Antenna %s", info->hdev->name,
							stat ? "out" : "in");
			}
			if (stat & 0x0001)
				bt3c_receive(info);
			if (stat & 0x0002) {
				//BT_ERR("Ack (stat=0x%04x)", stat);
				clear_bit(XMIT_SENDING, &(info->tx_state));
				bt3c_write_wakeup(info, 1);
			}

			bt3c_io_write(iobase, 0x7001, 0x0000);

			outb(iir, iobase + CONTROL);
		}
	}

	spin_unlock(&(info->lock));

	return IRQ_HANDLED;
}
Пример #3
0
static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
{
	bt3c_info_t *info = dev_inst;
	unsigned int iobase;
	int iir;

	if (!info) {
		printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq);
		return IRQ_NONE;
	}

	iobase = info->link.io.BasePort1;

	spin_lock(&(info->lock));

	iir = inb(iobase + CONTROL);
	if (iir & 0x80) {
		int stat = bt3c_read(iobase, 0x7001);

		if ((stat & 0xff) == 0x7f) {
			printk(KERN_WARNING "bt3c_cs: STRANGE stat=%04x\n", stat);
		} else if ((stat & 0xff) != 0xff) {
			if (stat & 0x0020) {
				int stat = bt3c_read(iobase, 0x7002) & 0x10;
				printk(KERN_WARNING "bt3c_cs: antena %s\n", stat ? "OUT" : "IN");
			}
			if (stat & 0x0001)
				bt3c_receive(info);
			if (stat & 0x0002) {
				//printk("bt3c_cs: ACK %04x\n", stat);
				clear_bit(XMIT_SENDING, &(info->tx_state));
				bt3c_write_wakeup(info, 1);
			}

			bt3c_io_write(iobase, 0x7001, 0x0000);

			outb(iir, iobase + CONTROL);
		}
	}

	spin_unlock(&(info->lock));

	return IRQ_HANDLED;
}
Пример #4
0
static void
bt3c_swi_intr(void *context)
{
	bt3c_softc_p	sc = (bt3c_softc_p) context;
	u_int16_t	data;

	/* Receive complete */
	if (sc->status & 0x0001) {
		sc->status &= ~0x0001; /* XXX is it safe? */

		if (ng_send_fn(sc->node, NULL, &bt3c_forward, NULL, 0) != 0)
			NG_BT3C_ALERT(sc->dev, "Could not forward frames!\n");
	}

	/* Send complete */
	if (sc->status & 0x0002) {
		sc->status &= ~0x0002; /* XXX is it safe */

		if (ng_send_fn(sc->node, NULL, &bt3c_send, NULL, 1) != 0)
			NG_BT3C_ALERT(sc->dev, "Could not send frames!\n");
	}

	/* Antenna position */
	if (sc->status & 0x0020) { 
		sc->status &= ~0x0020; /* XXX is it safe */

		bt3c_read(sc, 0x7002, data);
		data &= 0x10;

		if (data)
			sc->flags |= BT3C_ANTENNA_OUT;
		else
			sc->flags &= ~BT3C_ANTENNA_OUT;

		NG_BT3C_INFO(sc->dev, "Antenna %s\n", data? "OUT" : "IN");
	}
} /* bt3c_swi_intr */
Пример #5
0
/*
 * receive incoming data from device, store in mbuf chain and
 * pass on complete packets to bt device
 */
static void
bt3c_receive(struct bt3c_softc *sc)
{
	struct mbuf *m = sc->sc_rxp;
	int space = 0;
	uint16_t count;
	uint8_t b;

	/*
	 * If we already started a packet, find the
	 * trailing end of it.
	 */
	if (m) {
		while (m->m_next)
			m = m->m_next;

		space = M_TRAILINGSPACE(m);
	}

	count = bt3c_read(sc, BT3C_RX_COUNT);
	bt3c_set_address(sc, BT3C_RX_FIFO);

	while (count > 0) {
		if (space == 0) {
			if (m == NULL) {
				/* new packet */
				MGETHDR(m, M_DONTWAIT, MT_DATA);
				if (m == NULL) {
					aprint_error_dev(sc->sc_dev,
					    "out of memory\n");
					sc->sc_stats.err_rx++;
					goto out;	/* (lost sync) */
				}

				sc->sc_rxp = m;
				m->m_pkthdr.len = m->m_len = 0;
				space = MHLEN;

				sc->sc_state = BT3C_RECV_PKT_TYPE;
				sc->sc_want = 1;
			} else {
				/* extend mbuf */
				MGET(m->m_next, M_DONTWAIT, MT_DATA);
				if (m->m_next == NULL) {
					aprint_error_dev(sc->sc_dev,
					    "out of memory\n");
					sc->sc_stats.err_rx++;
					goto out;	/* (lost sync) */
				}

				m = m->m_next;
				m->m_len = 0;
				space = MLEN;

				if (sc->sc_want > MINCLSIZE) {
					MCLGET(m, M_DONTWAIT);
					if (m->m_flags & M_EXT)
						space = MCLBYTES;
				}
			}
		}

		b = bt3c_get(sc);
		mtod(m, uint8_t *)[m->m_len++] = b;
		count--;
		space--;
		sc->sc_rxp->m_pkthdr.len++;
		sc->sc_stats.byte_rx++;

		sc->sc_want--;
		if (sc->sc_want > 0)
			continue; /* want more */

		switch (sc->sc_state) {
		case BT3C_RECV_PKT_TYPE:		/* Got packet type */

			switch (b) {
			case HCI_ACL_DATA_PKT:
				sc->sc_state = BT3C_RECV_ACL_HDR;
				sc->sc_want = sizeof(hci_acldata_hdr_t) - 1;
				break;

			case HCI_SCO_DATA_PKT:
				sc->sc_state = BT3C_RECV_SCO_HDR;
				sc->sc_want = sizeof(hci_scodata_hdr_t) - 1;
				break;

			case HCI_EVENT_PKT:
				sc->sc_state = BT3C_RECV_EVENT_HDR;
				sc->sc_want = sizeof(hci_event_hdr_t) - 1;
				break;

			default:
				aprint_error_dev(sc->sc_dev,
				    "Unknown packet type=%#x!\n", b);
				sc->sc_stats.err_rx++;
				m_freem(sc->sc_rxp);
				sc->sc_rxp = NULL;
				goto out;	/* (lost sync) */
			}

			break;

		/*
		 * we assume (correctly of course :) that the packet headers
		 * all fit into a single pkthdr mbuf
		 */
		case BT3C_RECV_ACL_HDR:		/* Got ACL Header */
			sc->sc_state = BT3C_RECV_ACL_DATA;
			sc->sc_want = mtod(m, hci_acldata_hdr_t *)->length;
			sc->sc_want = le16toh(sc->sc_want);
			break;

		case BT3C_RECV_SCO_HDR:		/* Got SCO Header */
			sc->sc_state = BT3C_RECV_SCO_DATA;
			sc->sc_want =  mtod(m, hci_scodata_hdr_t *)->length;
			break;

		case BT3C_RECV_EVENT_HDR:	/* Got Event Header */
			sc->sc_state = BT3C_RECV_EVENT_DATA;
			sc->sc_want =  mtod(m, hci_event_hdr_t *)->length;
			break;

		case BT3C_RECV_ACL_DATA:	/* ACL Packet Complete */
			if (!hci_input_acl(sc->sc_unit, sc->sc_rxp))
				sc->sc_stats.err_rx++;

			sc->sc_stats.acl_rx++;
			sc->sc_rxp = m = NULL;
			space = 0;
			break;

		case BT3C_RECV_SCO_DATA:	/* SCO Packet Complete */
			if (!hci_input_sco(sc->sc_unit, sc->sc_rxp))
				sc->sc_stats.err_rx++;

			sc->sc_stats.sco_rx++;
			sc->sc_rxp = m = NULL;
			space = 0;
			break;

		case BT3C_RECV_EVENT_DATA:	/* Event Packet Complete */
			if (!hci_input_event(sc->sc_unit, sc->sc_rxp))
				sc->sc_stats.err_rx++;

			sc->sc_stats.evt_rx++;
			sc->sc_rxp = m = NULL;
			space = 0;
			break;

		default:
			panic("%s: invalid state %d!\n",
				device_xname(sc->sc_dev), sc->sc_state);
		}
	}

out:
	bt3c_write(sc, BT3C_RX_COUNT, 0x0000);
}
Пример #6
0
static void
bt3c_receive(bt3c_softc_p sc)
{
	u_int16_t	i, count, c;

	/* Receive data from the card */
	bt3c_read(sc, 0x7006, count);
	NG_BT3C_INFO(sc->dev, "The card has %d characters\n", count);

	bt3c_set_address(sc, 0x7480);

	for (i = 0; i < count; i++) {
		/* Allocate new mbuf if needed */
		if (sc->m == NULL) {
			sc->state = NG_BT3C_W4_PKT_IND;
			sc->want = 1;

			MGETHDR(sc->m, M_NOWAIT, MT_DATA);
			if (sc->m == NULL) {
				NG_BT3C_ERR(sc->dev, "Could not get mbuf\n");
				NG_BT3C_STAT_IERROR(sc->stat);

				break; /* XXX lost of sync */
			}

			if (!(MCLGET(sc->m, M_NOWAIT))) {
				NG_FREE_M(sc->m);

				NG_BT3C_ERR(sc->dev, "Could not get cluster\n");
				NG_BT3C_STAT_IERROR(sc->stat);

				break; /* XXX lost of sync */
			}

			sc->m->m_len = sc->m->m_pkthdr.len = 0;
		}

		/* Read and append character to mbuf */
		bt3c_read_data(sc, c);
		if (sc->m->m_pkthdr.len >= MCLBYTES) {
			NG_BT3C_ERR(sc->dev, "Oversized frame\n");
	
			NG_FREE_M(sc->m);
			sc->state = NG_BT3C_W4_PKT_IND;
			sc->want = 1;

			break; /* XXX lost of sync */
		}

		mtod(sc->m, u_int8_t *)[sc->m->m_len ++] = (u_int8_t) c;
		sc->m->m_pkthdr.len ++;

		NG_BT3C_INFO(sc->dev,
"Got char %#x, want=%d, got=%d\n", c, sc->want, sc->m->m_pkthdr.len);

		if (sc->m->m_pkthdr.len < sc->want)
			continue; /* wait for more */

		switch (sc->state) {
		/* Got packet indicator */
		case NG_BT3C_W4_PKT_IND:
			NG_BT3C_INFO(sc->dev,
"Got packet indicator %#x\n", *mtod(sc->m, u_int8_t *));

			sc->state = NG_BT3C_W4_PKT_HDR;

			/*
			 * Since packet indicator included in the packet 
			 * header just set sc->want to sizeof(packet header).
			 */

			switch (*mtod(sc->m, u_int8_t *)) {
			case NG_HCI_ACL_DATA_PKT:
				sc->want = sizeof(ng_hci_acldata_pkt_t);
				break;

			case NG_HCI_SCO_DATA_PKT:
				sc->want = sizeof(ng_hci_scodata_pkt_t);
				break;

			case NG_HCI_EVENT_PKT:
				sc->want = sizeof(ng_hci_event_pkt_t);
				break;

			default:
       	                	NG_BT3C_ERR(sc->dev,
"Ignoring unknown packet type=%#x\n", *mtod(sc->m, u_int8_t *));

				NG_BT3C_STAT_IERROR(sc->stat);

				NG_FREE_M(sc->m);
				sc->state = NG_BT3C_W4_PKT_IND;
				sc->want = 1;
				break;
			}
			break;

		/* Got packet header */
		case NG_BT3C_W4_PKT_HDR:
			sc->state = NG_BT3C_W4_PKT_DATA;

			switch (*mtod(sc->m, u_int8_t *)) {
			case NG_HCI_ACL_DATA_PKT:
				c = le16toh(mtod(sc->m,
					ng_hci_acldata_pkt_t *)->length);
				break;

			case NG_HCI_SCO_DATA_PKT:
				c = mtod(sc->m, ng_hci_scodata_pkt_t*)->length;
				break;

			case NG_HCI_EVENT_PKT:
				c = mtod(sc->m, ng_hci_event_pkt_t *)->length;
				break;

			default:
				KASSERT(0,
("Invalid packet type=%#x\n", *mtod(sc->m, u_int8_t *)));
				break;
       	        	 }

			NG_BT3C_INFO(sc->dev,
"Got packet header, packet type=%#x, got so far %d, payload size=%d\n",
				*mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len,
				c);

			if (c > 0) {
				sc->want += c;
				break;
			}

			/* else FALLTHROUGH and deliver frame */
			/* XXX is this true? should we deliver empty frame? */

		/* Got packet data */
		case NG_BT3C_W4_PKT_DATA:
			NG_BT3C_INFO(sc->dev,
"Got full packet, packet type=%#x, packet size=%d\n",
				*mtod(sc->m, u_int8_t *), sc->m->m_pkthdr.len);

			NG_BT3C_STAT_BYTES_RECV(sc->stat, sc->m->m_pkthdr.len);
			NG_BT3C_STAT_PCKTS_RECV(sc->stat);

			IF_LOCK(&sc->inq);
			if (_IF_QFULL(&sc->inq)) {
				NG_BT3C_ERR(sc->dev,
"Incoming queue is full. Dropping mbuf, len=%d\n", sc->m->m_pkthdr.len);

				NG_BT3C_STAT_IERROR(sc->stat);

				NG_FREE_M(sc->m);
			} else {
				_IF_ENQUEUE(&sc->inq, sc->m);
				sc->m = NULL;
			}
			IF_UNLOCK(&sc->inq);

			sc->state = NG_BT3C_W4_PKT_IND;
			sc->want = 1;
			break;

		default:
			KASSERT(0,
("Invalid node state=%d", sc->state));
			break;
		}
	}

	bt3c_write(sc, 0x7006, 0x0000);
} /* bt3c_receive */
Пример #7
0
static void bt3c_receive(bt3c_info_t *info)
{
	unsigned int iobase;
	int size = 0, avail;

	if (!info) {
		printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n");
		return;
	}

	iobase = info->link.io.BasePort1;

	avail = bt3c_read(iobase, 0x7006);
	//printk("bt3c_cs: receiving %d bytes\n", avail);

	bt3c_address(iobase, 0x7480);
	while (size < avail) {
		size++;
		info->hdev.stat.byte_rx++;

		/* Allocate packet */
		if (info->rx_skb == NULL) {
			info->rx_state = RECV_WAIT_PACKET_TYPE;
			info->rx_count = 0;
			if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
				printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n");
				return;
			}
		}


		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {

			info->rx_skb->dev = (void *)&(info->hdev);
			info->rx_skb->pkt_type = inb(iobase + DATA_L);
			inb(iobase + DATA_H);
			//printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type);

			switch (info->rx_skb->pkt_type) {

			case HCI_EVENT_PKT:
				info->rx_state = RECV_WAIT_EVENT_HEADER;
				info->rx_count = HCI_EVENT_HDR_SIZE;
				break;

			case HCI_ACLDATA_PKT:
				info->rx_state = RECV_WAIT_ACL_HEADER;
				info->rx_count = HCI_ACL_HDR_SIZE;
				break;

			case HCI_SCODATA_PKT:
				info->rx_state = RECV_WAIT_SCO_HEADER;
				info->rx_count = HCI_SCO_HDR_SIZE;
				break;

			default:
				/* Unknown packet */
				printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
				info->hdev.stat.err_rx++;
				clear_bit(HCI_RUNNING, &(info->hdev.flags));

				dev_kfree_skb_any(info->rx_skb);
				info->rx_skb = NULL;
				break;

			}

		} else {

			__u8 x = inb(iobase + DATA_L);

			*skb_put(info->rx_skb, 1) = x;
			inb(iobase + DATA_H);
			info->rx_count--;

			if (info->rx_count == 0) {

				int dlen;
				struct hci_event_hdr *eh;
				struct hci_acl_hdr *ah;
				struct hci_sco_hdr *sh;

				switch (info->rx_state) {

				case RECV_WAIT_EVENT_HEADER:
					eh = (struct hci_event_hdr *)(info->rx_skb->data);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = eh->plen;
					break;

				case RECV_WAIT_ACL_HEADER:
					ah = (struct hci_acl_hdr *)(info->rx_skb->data);
					dlen = __le16_to_cpu(ah->dlen);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = dlen;
					break;

				case RECV_WAIT_SCO_HEADER:
					sh = (struct hci_sco_hdr *)(info->rx_skb->data);
					info->rx_state = RECV_WAIT_DATA;
					info->rx_count = sh->dlen;
					break;

				case RECV_WAIT_DATA:
					hci_recv_frame(info->rx_skb);
					info->rx_skb = NULL;
					break;

				}

			}

		}

	}

	bt3c_io_write(iobase, 0x7006, 0x0000);
}