/**
 * Process root hub request.
 *
 * @param instance Root hub instance
 * @param request Structure containing both request and response information
 * @return Error code
 */
void rh_request(rh_t *instance, usb_transfer_batch_t *request)
{
	assert(instance);
	assert(request);

	switch (request->ep->transfer_type)
	{
	case USB_TRANSFER_CONTROL:
		usb_log_debug("Root hub got CONTROL packet\n");
		control_request(instance, request);
		break;

	case USB_TRANSFER_INTERRUPT:
		usb_log_debug("Root hub got INTERRUPT packet\n");
		fibril_mutex_lock(&instance->guard);
		assert(instance->unfinished_interrupt_transfer == NULL);
		const uint16_t mask = create_interrupt_mask(instance);
		if (mask == 0) {
			usb_log_debug("No changes(%hx)...\n", mask);
			instance->unfinished_interrupt_transfer = request;
		} else {
			usb_log_debug("Processing changes...\n");
			interrupt_request(
			    request, mask, instance->interrupt_mask_size);
		}
		fibril_mutex_unlock(&instance->guard);
		break;

	default:
		usb_log_error("Root hub got unsupported request.\n");
		TRANSFER_END(request, ENOTSUP);
	}
}
Exemple #2
0
static void
do_work( void )
{
	struct iovec vec[MAX_IOVEC];
	int n, count;

	union {
		void ** v;
		char ** c;
	} iovec_pun;

	n = count = 0;

	for( ;; ) {
		ablk_req_head_t *cur = &ablk.ring[ ablk.req_head ];
		int proceed = cur->proceed;
		int f, next = NEXT( ablk.req_head );
		ablk_req_head_t *r = &ablk.ring[next];

		/* execute request? */
		if( n && (!proceed || n == MAX_IOVEC || !(r->flags & ABLK_SG_BUF)) ) {
			int ret;

			while( (ret=(*ablk.iofunc)(ablk.devs[ablk.cur_dev].bdev, vec, n)) != count ) {
				int s, i;
				for( i=0; ret > 0; i++, ret -= s, count -= s ) {
					s = MIN( vec[i].iov_len, ret );
					vec[i].iov_len -= s;
					vec[i].iov_base += s;
				}
				if( ret < 0 && errno != EINTR ) {
					perrorm("ablk iofunc");
					goto error;
				}
			}
			ablk.n_requests += n;

			/* this takes into account the engine stall interrupt */
			if( (cur->flags & ABLK_RAISE_IRQ) && proceed )
				irq_line_hi( ablk.irq );
			n = 0;
			count = 0;
		}
		/* engine stall? */
		if( !proceed )
			break;

		/* flag old head slot for reuse */
		cur->flags = 0;

		/* advance pointer to next request */
		cur->proceed = 0;
		f = r->flags;
		ablk.req_head = next;

		/* process scatter & gather bufs */
		if( (f & ABLK_SG_BUF) ) {
			ablk_sg_t *p = (ablk_sg_t*)r;
			iovec_pun.v = &(vec[n].iov_base);
			if( mphys_to_lvptr( p->buf, (char**)iovec_pun.c ) ) {
				printm("ablk: bogus sg-buf");
				goto error;
			}
			vec[n++].iov_len = p->count;
			count += p->count;

			/* req_count is increased when the request is finished */
			continue;
		}

		/* must be a read/write/cntrol request */
		if( (unsigned int)r->unit >= ablk.ndevs ) {
			printm("ablk: bad unit");
			goto error;
		}
		ablk.cur_dev = r->unit;
		/* Read / Write Request */
		if( f & (ABLK_READ_REQ | ABLK_WRITE_REQ) ) {
			/* Schedule the next iofunc */
			ablk.iofunc = (f & ABLK_WRITE_REQ)? ablk.devs[r->unit].bdev->write : ablk.devs[r->unit].bdev->read;
			/* r->param contains first sector */
			if( ablk.devs[r->unit].bdev->seek( ablk.devs[r->unit].bdev, r->param, 0 ) < 0 ) {
				printm("ablk: bad lseek");
				goto error;
			}
		} else if( f & ABLK_CNTRL_REQ_MASK) {
			ablk.iofunc = control_request( ablk.devs[r->unit].bdev, (f & ABLK_CNTRL_REQ_MASK), r->param );
			if( f & ABLK_RAISE_IRQ )
				irq_line_hi( ablk.irq );
		} else {
			printm("bogus ablk command!\n");
			goto error;
		}
		/* n and count have already been set to zero */
		ablk.n_requests++;
	}

	/* engine stall */
	ablk.active = 0;
	irq_line_hi( ablk.irq );
	return;

 error:
	printm("ABlk engine error\n");
	ablk.running = 0;
	ablk.active = 0;

	irq_line_hi( ablk.irq );
}