Example #1
0
/* remove queue from device schedule, dropping all data that came in */
static void
uhci_destroy_intr_queue (endpoint_t *ep, void *q_)
{
	intr_q *q = (intr_q*)q_;
	u32 val = virt_to_phys (q->qh);
	u32 end = virt_to_phys (UHCI_INST (ep->dev->controller)->qh_intr);
	int i;
	for (i=0; i<1024; i++) {
		u32 oldptr = 0;
		u32 ptr = UHCI_INST (ep->dev->controller)->framelistptr[i].ptr;
		while (ptr != end) {
			if (((qh_t*)phys_to_virt(ptr))->elementlinkptr.ptr == val) {
				((qh_t*)phys_to_virt(oldptr))->headlinkptr.ptr = ((qh_t*)phys_to_virt(ptr))->headlinkptr.ptr;
				free(phys_to_virt(ptr));
				break;
			}
			oldptr = ptr;
			ptr = ((qh_t*)phys_to_virt(ptr))->headlinkptr.ptr;
		}
	}
	free(q->data);
	free(q->tds);
	free(q->qh);
	free(q);
}
Example #2
0
static int
run_schedule (usbdev_t *dev, td_t *td)
{
	UHCI_INST (dev->controller)->qh_data->elementlinkptr =
		virt_to_phys (td) & ~(FLISTP_QH | FLISTP_TERMINATE);
	td = wait_for_completed_qh (dev->controller,
				    UHCI_INST (dev->controller)->qh_data);
	if (td == 0) {
		return 0;
	} else {
		td_dump (td);
		return 1;
	}
}
Example #3
0
static void
uhci_reset (hci_t *controller)
{
	/* reset */
	uhci_reg_write16 (controller, USBCMD, 4);
	mdelay (50);
	uhci_reg_write16 (controller, USBCMD, 0);
	mdelay (10);
	uhci_reg_write16 (controller, USBCMD, 2);
	while ((uhci_reg_read16 (controller, USBCMD) & 2) != 0)
		mdelay (1);

	uhci_reg_write32 (controller, FLBASEADD,
			  (u32) virt_to_phys (UHCI_INST (controller)->
					      framelistptr));
	//debug ("framelist at %p\n",UHCI_INST(controller)->framelistptr);

	/* disable irqs */
	uhci_reg_write16 (controller, USBINTR, 0);

	/* reset framelist index */
	uhci_reg_write16 (controller, FRNUM, 0);

	uhci_reg_mask16 (controller, USBCMD, ~0, 0xc0);	// max packets, configure flag

	uhci_start (controller);
}
Example #4
0
static int
run_schedule (usbdev_t *dev, td_t *td)
{
	UHCI_INST (dev->controller)->qh_data->elementlinkptr.ptr =
		virt_to_phys (td);
	UHCI_INST (dev->controller)->qh_data->elementlinkptr.queue_head = 0;
	UHCI_INST (dev->controller)->qh_data->elementlinkptr.terminate = 0;
	td = wait_for_completed_qh (dev->controller,
				    UHCI_INST (dev->controller)->qh_data);
	if (td == 0) {
		return 0;
	} else {
		td_dump (td);
		return 1;
	}
}
Example #5
0
static void
uhci_shutdown (hci_t *controller)
{
	if (controller == 0)
		return;
	detach_controller (controller);
	UHCI_INST (controller)->roothub->destroy (UHCI_INST (controller)->
						  roothub);
	uhci_reg_mask16 (controller, USBCMD, 0, 0);	// stop work
	free (UHCI_INST (controller)->framelistptr);
	free (UHCI_INST (controller)->qh_prei);
	free (UHCI_INST (controller)->qh_intr);
	free (UHCI_INST (controller)->qh_data);
	free (UHCI_INST (controller)->qh_last);
	free (UHCI_INST (controller));
	free (controller);
}
Example #6
0
static void
uhci_reinit (hci_t *controller)
{
	uhci_reg_write32 (controller, FLBASEADD,
			  (u32) virt_to_phys (UHCI_INST (controller)->
					      framelistptr));
	//usb_debug ("framelist at %p\n",UHCI_INST(controller)->framelistptr);

	/* disable irqs */
	uhci_reg_write16 (controller, USBINTR, 0);

	/* reset framelist index */
	uhci_reg_write16 (controller, FRNUM, 0);

	uhci_reg_write16(controller, USBCMD,
			 uhci_reg_read16(controller, USBCMD) | 0xc0);	// max packets, configure flag

	uhci_start (controller);
}
Example #7
0
/* remove queue from device schedule, dropping all data that came in */
static void
uhci_destroy_intr_queue (endpoint_t *ep, void *q_)
{
	intr_q *const q = (intr_q*)q_;

	/* remove QH from framelist */
	uhci_t *const uhcic = UHCI_INST(ep->dev->controller);
	const u32 qh_ptr = virt_to_phys(q->qh) | FLISTP_QH;
	const u32 def_ptr = virt_to_phys(uhcic->qh_prei) | FLISTP_QH;
	int i;
	for (i = 0; i < 1024; ++i) {
		if (uhcic->framelistptr[i] == qh_ptr)
			uhcic->framelistptr[i] = def_ptr;
	}

	free(q->data);
	free(q->tds);
	free(q->qh);
	free(q);
}
Example #8
0
/* create and hook-up an intr queue into device schedule */
static void*
uhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming)
{
	u8 *data = malloc(reqsize*reqcount);
	td_t *tds = memalign(16, sizeof(td_t) * reqcount);
	qh_t *qh = memalign(16, sizeof(qh_t));

	if (!data || !tds || !qh)
		fatal("Not enough memory to create USB intr queue prerequisites.\n");

	qh->elementlinkptr = virt_to_phys(tds);

	intr_q *q = malloc(sizeof(intr_q));
	if (!q)
		fatal("Not enough memory to create USB intr queue.\n");
	q->qh = qh;
	q->tds = tds;
	q->data = data;
	q->lastread = 0;
	q->total = reqcount;
	q->reqsize = reqsize;
	q->last_td = &tds[reqcount - 1];

	memset (tds, 0, sizeof (td_t) * reqcount);
	int i;
	for (i = 0; i < reqcount; i++) {
		tds[i].ptr = virt_to_phys (&tds[i + 1]);

		switch (ep->direction) {
			case IN: tds[i].token = UHCI_IN; break;
			case OUT: tds[i].token = UHCI_OUT; break;
			case SETUP: tds[i].token = UHCI_SETUP; break;
		}
		tds[i].token |= ep->dev->address << TD_DEVADDR_SHIFT |
			(ep->endpoint & 0xf) << TD_EP_SHIFT |
			maxlen (reqsize) << TD_MAXLEN_SHIFT |
			(ep->toggle & 1) << TD_TOGGLE_SHIFT;
		tds[i].bufptr = virt_to_phys (data);
		tds[i].ctrlsts = (0 << TD_COUNTER_SHIFT) |
			(ep->dev->speed?TD_LOWSPEED:0) |
			TD_STATUS_ACTIVE;
		ep->toggle ^= 1;
		data += reqsize;
	}
	tds[reqcount - 1].ptr = 0 | TD_TERMINATE;

	/* insert QH into framelist */
	uhci_t *const uhcic = UHCI_INST(ep->dev->controller);
	const u32 def_ptr = virt_to_phys(uhcic->qh_prei) | FLISTP_QH;
	int nothing_placed = 1;
	qh->headlinkptr = def_ptr;
	for (i = 0; i < 1024; i += reqtiming) {
		/* advance to the next free position */
		while ((i < 1024) && (uhcic->framelistptr[i] != def_ptr)) ++i;
		if (i < 1024) {
			uhcic->framelistptr[i] = virt_to_phys(qh) | FLISTP_QH;
			nothing_placed = 0;
		}
	}
	if (nothing_placed) {
		usb_debug("Error: Failed to place UHCI interrupt queue "
			      "head into framelist: no space left\n");
		uhci_destroy_intr_queue(ep, q);
		return NULL;
	}

	return q;
}
Example #9
0
static int
uhci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen,
	      unsigned char *data)
{
	int endp = 0;		/* this is control: always 0 */
	int mlen = dev->endpoints[0].maxpacketsize;
	int count = (2 + (dalen + mlen - 1) / mlen);
	unsigned short req = ((unsigned short *) devreq)[0];
	int i;
	td_t *tds = memalign (16, sizeof (td_t) * count);
	memset (tds, 0, sizeof (td_t) * count);
	count--;		/* to compensate for 0-indexed array */
	for (i = 0; i < count; i++) {
		tds[i].ptr = virt_to_phys (&tds[i + 1]) | TD_DEPTH_FIRST;
	}
	tds[count].ptr = 0 | TD_DEPTH_FIRST | TD_TERMINATE;

	tds[0].token = UHCI_SETUP |
		dev->address << TD_DEVADDR_SHIFT |
		endp << TD_EP_SHIFT |
		TD_TOGGLE_DATA0 |
		maxlen(drlen) << TD_MAXLEN_SHIFT;
	tds[0].bufptr = virt_to_phys (devreq);
	tds[0].ctrlsts = (3 << TD_COUNTER_SHIFT) |
		(dev->speed?TD_LOWSPEED:0) |
		TD_STATUS_ACTIVE;

	int toggle = 1;
	for (i = 1; i < count; i++) {
		switch (dir) {
			case SETUP: tds[i].token = UHCI_SETUP; break;
			case IN:    tds[i].token = UHCI_IN;    break;
			case OUT:   tds[i].token = UHCI_OUT;   break;
		}
		tds[i].token |= dev->address << TD_DEVADDR_SHIFT |
			endp << TD_EP_SHIFT |
			maxlen (min (mlen, dalen)) << TD_MAXLEN_SHIFT |
			toggle << TD_TOGGLE_SHIFT;
		tds[i].bufptr = virt_to_phys (data);
		tds[i].ctrlsts = (3 << TD_COUNTER_SHIFT) |
			(dev->speed?TD_LOWSPEED:0) |
			TD_STATUS_ACTIVE;
		toggle ^= 1;
		dalen -= mlen;
		data += mlen;
	}

	tds[count].token = ((dir == OUT) ? UHCI_IN : UHCI_OUT) |
		dev->address << TD_DEVADDR_SHIFT |
		endp << TD_EP_SHIFT |
		maxlen(0) << TD_MAXLEN_SHIFT |
		TD_TOGGLE_DATA1;
	tds[count].bufptr = 0;
	tds[count].ctrlsts = (0 << TD_COUNTER_SHIFT) | /* as Linux 2.4.10 does */
		(dev->speed?TD_LOWSPEED:0) |
		TD_STATUS_ACTIVE;
	UHCI_INST (dev->controller)->qh_data->elementlinkptr =
		virt_to_phys (tds) & ~(FLISTP_QH | FLISTP_TERMINATE);
	td_t *td = wait_for_completed_qh (dev->controller,
					  UHCI_INST (dev->controller)->
					  qh_data);
	int result;
	if (td == 0) {
		result = 0;
	} else {
		usb_debug ("control packet, req %x\n", req);
		td_dump (td);
		result = 1;
	}
	free (tds);
	return result;
}
Example #10
0
hci_t *
uhci_init (pcidev_t addr)
{
	int i;
	u16 reg16;

	hci_t *controller = new_controller ();

	if (!controller)
		fatal("Could not create USB controller instance.\n");

	controller->instance = malloc (sizeof (uhci_t));
	if(!controller->instance)
		fatal("Not enough memory creating USB controller instance.\n");

	controller->type = UHCI;

	controller->start = uhci_start;
	controller->stop = uhci_stop;
	controller->reset = uhci_reset;
	controller->init = uhci_reinit;
	controller->shutdown = uhci_shutdown;
	controller->bulk = uhci_bulk;
	controller->control = uhci_control;
	controller->set_address = generic_set_address;
	controller->finish_device_config = NULL;
	controller->destroy_device = NULL;
	controller->create_intr_queue = uhci_create_intr_queue;
	controller->destroy_intr_queue = uhci_destroy_intr_queue;
	controller->poll_intr_queue = uhci_poll_intr_queue;
	for (i = 0; i < 128; i++) {
		controller->devices[i] = 0;
	}
	init_device_entry (controller, 0);
	UHCI_INST (controller)->roothub = controller->devices[0];

	controller->bus_address = addr;
	controller->reg_base = pci_read_config32 (controller->bus_address, 0x20) & ~1;	/* ~1 clears the register type indicator that is set to 1 for IO space */

	/* kill legacy support handler */
	uhci_stop (controller);
	mdelay (1);
	uhci_reg_write16 (controller, USBSTS, 0x3f);
	reg16 = pci_read_config16(controller->bus_address, 0xc0);
	reg16 &= 0xdf80;
	pci_write_config16 (controller->bus_address, 0xc0, reg16);

	UHCI_INST (controller)->framelistptr = memalign (0x1000, 1024 * sizeof (flistp_t));	/* 4kb aligned to 4kb */
	if (! UHCI_INST (controller)->framelistptr)
		fatal("Not enough memory for USB frame list pointer.\n");

	memset (UHCI_INST (controller)->framelistptr, 0,
		1024 * sizeof (flistp_t));

	/* According to the *BSD UHCI code, this one is needed on some
	   PIIX chips, because otherwise they misbehave. It must be
	   added to the last chain.

	   FIXME: this leaks, if the driver should ever be reinited
	          for some reason. Not a problem now.
	   */
	td_t *antiberserk = memalign(16, sizeof(td_t));
	if (!antiberserk)
		fatal("Not enough memory for chipset workaround.\n");
	memset(antiberserk, 0, sizeof(td_t));

	UHCI_INST (controller)->qh_prei = memalign (16, sizeof (qh_t));
	UHCI_INST (controller)->qh_intr = memalign (16, sizeof (qh_t));
	UHCI_INST (controller)->qh_data = memalign (16, sizeof (qh_t));
	UHCI_INST (controller)->qh_last = memalign (16, sizeof (qh_t));

	if (! UHCI_INST (controller)->qh_prei ||
	    ! UHCI_INST (controller)->qh_intr ||
	    ! UHCI_INST (controller)->qh_data ||
	    ! UHCI_INST (controller)->qh_last)
		fatal("Not enough memory for USB controller queues.\n");

	UHCI_INST (controller)->qh_prei->headlinkptr =
		virt_to_phys (UHCI_INST (controller)->qh_intr) | FLISTP_QH;
	UHCI_INST (controller)->qh_prei->elementlinkptr = 0 | FLISTP_TERMINATE;

	UHCI_INST (controller)->qh_intr->headlinkptr =
		virt_to_phys (UHCI_INST (controller)->qh_data) | FLISTP_QH;
	UHCI_INST (controller)->qh_intr->elementlinkptr = 0 | FLISTP_TERMINATE;

	UHCI_INST (controller)->qh_data->headlinkptr =
		virt_to_phys (UHCI_INST (controller)->qh_last) | FLISTP_QH;
	UHCI_INST (controller)->qh_data->elementlinkptr = 0 | FLISTP_TERMINATE;

	UHCI_INST (controller)->qh_last->headlinkptr = virt_to_phys (UHCI_INST (controller)->qh_data) | FLISTP_TERMINATE;
	UHCI_INST (controller)->qh_last->elementlinkptr = virt_to_phys (antiberserk) | FLISTP_TERMINATE;

	for (i = 0; i < 1024; i++) {
		UHCI_INST (controller)->framelistptr[i] =
			virt_to_phys (UHCI_INST (controller)->qh_prei) | FLISTP_QH;
	}
	controller->devices[0]->controller = controller;
	controller->devices[0]->init = uhci_rh_init;
	controller->devices[0]->init (controller->devices[0]);
	uhci_reset (controller);
	uhci_reinit (controller);
	return controller;
}
Example #11
0
/* create and hook-up an intr queue into device schedule */
static void*
uhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming)
{
	u8 *data = malloc(reqsize*reqcount);
	td_t *tds = memalign(16, sizeof(td_t) * reqcount);
	qh_t *qh = memalign(16, sizeof(qh_t));

	if (!data || !tds || !qh)
		fatal("Not enough memory to create USB intr queue prerequisites.\n");

	qh->elementlinkptr.ptr = virt_to_phys(tds);
	qh->elementlinkptr.queue_head = 0;
	qh->elementlinkptr.terminate = 0;

	intr_q *q = malloc(sizeof(intr_q));
	if (!q)
		fatal("Not enough memory to create USB intr queue.\n");
	q->qh = qh;
	q->tds = tds;
	q->data = data;
	q->lastread = 0;
	q->total = reqcount;
	q->reqsize = reqsize;
	q->last_td = &tds[reqcount - 1];

	memset (tds, 0, sizeof (td_t) * reqcount);
	int i;
	for (i = 0; i < reqcount; i++) {
		tds[i].ptr = virt_to_phys (&tds[i + 1]);
		tds[i].terminate = 0;
		tds[i].queue_head = 0;
		tds[i].depth_first = 0;

		switch (ep->direction) {
			case IN: tds[i].pid = UHCI_IN; break;
			case OUT: tds[i].pid = UHCI_OUT; break;
			case SETUP: tds[i].pid = UHCI_SETUP; break;
		}
		tds[i].dev_addr = ep->dev->address;
		tds[i].endp = ep->endpoint & 0xf;
		tds[i].maxlen = maxlen (reqsize);
		tds[i].counter = 0;
		tds[i].data_toggle = ep->toggle & 1;
		tds[i].lowspeed = ep->dev->speed;
		tds[i].bufptr = virt_to_phys (data);
		tds[i].status_active = 1;
		ep->toggle ^= 1;
		data += reqsize;
	}
	tds[reqcount - 1].ptr = 0;
	tds[reqcount - 1].terminate = 1;
	tds[reqcount - 1].queue_head = 0;
	tds[reqcount - 1].depth_first = 0;
	for (i = reqtiming; i < 1024; i += reqtiming) {
		/* FIXME: wrap in another qh, one for each occurance of the qh in the framelist */
		qh->headlinkptr.ptr = UHCI_INST (ep->dev->controller)->framelistptr[i].ptr;
		qh->headlinkptr.terminate = 0;
		UHCI_INST (ep->dev->controller)->framelistptr[i].ptr = virt_to_phys(qh);
		UHCI_INST (ep->dev->controller)->framelistptr[i].terminate = 0;
		UHCI_INST (ep->dev->controller)->framelistptr[i].queue_head = 1;
	}
	return q;
}
Example #12
0
static int
uhci_control (usbdev_t *dev, direction_t dir, int drlen, void *devreq, int dalen,
	      unsigned char *data)
{
	int endp = 0;		/* this is control: always 0 */
	int mlen = dev->endpoints[0].maxpacketsize;
	int count = (2 + (dalen + mlen - 1) / mlen);
	unsigned short req = ((unsigned short *) devreq)[0];
	int i;
	td_t *tds = memalign (16, sizeof (td_t) * count);
	memset (tds, 0, sizeof (td_t) * count);
	count--;		/* to compensate for 0-indexed array */
	for (i = 0; i < count; i++) {
		tds[i].ptr = virt_to_phys (&tds[i + 1]);
		tds[i].depth_first = 1;
		tds[i].terminate = 0;
	}
	tds[count].ptr = 0;
	tds[count].depth_first = 1;
	tds[count].terminate = 1;

	tds[0].pid = UHCI_SETUP;
	tds[0].dev_addr = dev->address;
	tds[0].endp = endp;
	tds[0].maxlen = maxlen (drlen);
	tds[0].counter = 3;
	tds[0].data_toggle = 0;
	tds[0].lowspeed = dev->speed;
	tds[0].bufptr = virt_to_phys (devreq);
	tds[0].status_active = 1;

	int toggle = 1;
	for (i = 1; i < count; i++) {
		switch (dir) {
			case SETUP: tds[i].pid = UHCI_SETUP; break;
			case IN:    tds[i].pid = UHCI_IN;    break;
			case OUT:   tds[i].pid = UHCI_OUT;   break;
		}
		tds[i].dev_addr = dev->address;
		tds[i].endp = endp;
		tds[i].maxlen = maxlen (min (mlen, dalen));
		tds[i].counter = 3;
		tds[i].data_toggle = toggle;
		tds[i].lowspeed = dev->speed;
		tds[i].bufptr = virt_to_phys (data);
		tds[i].status_active = 1;
		toggle ^= 1;
		dalen -= mlen;
		data += mlen;
	}

	tds[count].pid = (dir == OUT) ? UHCI_IN : UHCI_OUT;
	tds[count].dev_addr = dev->address;
	tds[count].endp = endp;
	tds[count].maxlen = maxlen (0);
	tds[count].counter = 0;	/* as per linux 2.4.10 */
	tds[count].data_toggle = 1;
	tds[count].lowspeed = dev->speed;
	tds[count].bufptr = 0;
	tds[count].status_active = 1;
	UHCI_INST (dev->controller)->qh_data->elementlinkptr.ptr =
		virt_to_phys (tds);
	UHCI_INST (dev->controller)->qh_data->elementlinkptr.queue_head = 0;
	UHCI_INST (dev->controller)->qh_data->elementlinkptr.terminate = 0;
	td_t *td = wait_for_completed_qh (dev->controller,
					  UHCI_INST (dev->controller)->
					  qh_data);
	int result;
	if (td == 0) {
		result = 0;
	} else {
		debug ("control packet, req %x\n", req);
		td_dump (td);
		result = 1;
	}
	free (tds);
	return result;
}