⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gmidi.c

📁 linux下面gadget设备驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
	struct gmidi_device *dev = ep->driver_data;	/* cable is ignored, because for now we only have one. */	if (!dev->out_substream) {		/* Nobody is listening - throw it on the floor. */		return;	}	if (!test_bit(dev->out_substream->number, &dev->out_triggered)) {		return;	}	snd_rawmidi_receive(dev->out_substream, data, length);}static void gmidi_handle_out_data(struct usb_ep *ep, struct usb_request *req){	unsigned i;	u8 *buf = req->buf;	for (i = 0; i + 3 < req->actual; i += 4) {		if (buf[i] != 0) {			int cable = buf[i] >> 4;			int length = gmidi_cin_length[buf[i] & 0x0f];			gmidi_read_data(ep, cable, &buf[i + 1], length);		}	}}static void gmidi_complete(struct usb_ep *ep, struct usb_request *req){	struct gmidi_device *dev = ep->driver_data;	int status = req->status;	switch (status) {	case 0:				/* normal completion */		if (ep == dev->out_ep) {			/* we received stuff.			   req is queued again, below */			gmidi_handle_out_data(ep, req);		} else if (ep == dev->in_ep) {			/* our transmit completed.			   see if there's more to go.			   gmidi_transmit eats req, don't queue it again. */			gmidi_transmit(dev, req);			return;		}		break;	/* this endpoint is normally active while we're configured */	case -ECONNABORTED:		/* hardware forced ep reset */	case -ECONNRESET:		/* request dequeued */	case -ESHUTDOWN:		/* disconnect from host */		VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,				req->actual, req->length);		if (ep == dev->out_ep) {			gmidi_handle_out_data(ep, req);		}		free_ep_req(ep, req);		return;	case -EOVERFLOW:		/* buffer overrun on read means that					 * we didn't provide a big enough					 * buffer.					 */	default:		DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,				status, req->actual, req->length);		break;	case -EREMOTEIO:		/* short read */		break;	}	status = usb_ep_queue(ep, req, GFP_ATOMIC);	if (status) {		ERROR(dev, "kill %s:  resubmit %d bytes --> %d\n",				ep->name, req->length, status);		usb_ep_set_halt(ep);		/* FIXME recover later ... somehow */	}}static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags){	int err = 0;	struct usb_request *req;	struct usb_ep *ep;	unsigned i;	err = usb_ep_enable(dev->in_ep, &bulk_in_desc);	if (err) {		ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);		goto fail;	}	dev->in_ep->driver_data = dev;	err = usb_ep_enable(dev->out_ep, &bulk_out_desc);	if (err) {		ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);		goto fail;	}	dev->out_ep->driver_data = dev;	/* allocate a bunch of read buffers and queue them all at once. */	ep = dev->out_ep;	for (i = 0; i < qlen && err == 0; i++) {		req = alloc_ep_req(ep, buflen);		if (req) {			req->complete = gmidi_complete;			err = usb_ep_queue(ep, req, GFP_ATOMIC);			if (err) {				DBG(dev, "%s queue req: %d\n", ep->name, err);			}		} else {			err = -ENOMEM;		}	}fail:	/* caller is responsible for cleanup on error */	return err;}static void gmidi_reset_config(struct gmidi_device *dev){	if (dev->config == 0) {		return;	}	DBG(dev, "reset config\n");	/* just disable endpoints, forcing completion of pending i/o.	 * all our completion handlers free their requests in this case.	 */	usb_ep_disable(dev->in_ep);	usb_ep_disable(dev->out_ep);	dev->config = 0;}/* change our operational config.  this code must agree with the code * that returns config descriptors, and altsetting code. * * it's also responsible for power management interactions. some * configurations might not work with our current power sources. * * note that some device controller hardware will constrain what this * code can do, perhaps by disallowing more than one configuration or * by limiting configuration choices (like the pxa2xx). */static intgmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags){	int result = 0;	struct usb_gadget *gadget = dev->gadget;#if 0	/* FIXME */	/* Hacking this bit out fixes a bug where on receipt of two	   USB_REQ_SET_CONFIGURATION messages, we end up with no	   buffered OUT requests waiting for data. This is clearly	   hiding a bug elsewhere, because if the config didn't	   change then we really shouldn't do anything. */	/* Having said that, when we do "change" from config 1	   to config 1, we at least gmidi_reset_config() which	   clears out any requests on endpoints, so it's not like	   we leak or anything. */	if (number == dev->config) {		return 0;	}#endif	if (gadget_is_sa1100(gadget) && dev->config) {		/* tx fifo is full, but we can't clear it...*/		ERROR(dev, "can't change configurations\n");		return -ESPIPE;	}	gmidi_reset_config(dev);	switch (number) {	case GMIDI_CONFIG:		result = set_gmidi_config(dev, gfp_flags);		break;	default:		result = -EINVAL;		/* FALL THROUGH */	case 0:		return result;	}	if (!result && (!dev->in_ep || !dev->out_ep)) {		result = -ENODEV;	}	if (result) {		gmidi_reset_config(dev);	} else {		char *speed;		switch (gadget->speed) {		case USB_SPEED_LOW:	speed = "low"; break;		case USB_SPEED_FULL:	speed = "full"; break;		case USB_SPEED_HIGH:	speed = "high"; break;		default:		speed = "?"; break;		}		dev->config = number;		INFO(dev, "%s speed\n", speed);	}	return result;}static void gmidi_setup_complete(struct usb_ep *ep, struct usb_request *req){	if (req->status || req->actual != req->length) {		DBG((struct gmidi_device *) ep->driver_data,				"setup complete --> %d, %d/%d\n",				req->status, req->actual, req->length);	}}/* * The setup() callback implements all the ep0 functionality that's * not handled lower down, in hardware or the hardware driver (like * device and endpoint feature flags, and their status).  It's all * housekeeping for the gadget function we're implementing.  Most of * the work is in config-specific setup. */static int gmidi_setup(struct usb_gadget *gadget,			const struct usb_ctrlrequest *ctrl){	struct gmidi_device *dev = get_gadget_data(gadget);	struct usb_request *req = dev->req;	int value = -EOPNOTSUPP;	u16 w_index = le16_to_cpu(ctrl->wIndex);	u16 w_value = le16_to_cpu(ctrl->wValue);	u16 w_length = le16_to_cpu(ctrl->wLength);	/* usually this stores reply data in the pre-allocated ep0 buffer,	 * but config change events will reconfigure hardware.	 */	req->zero = 0;	switch (ctrl->bRequest) {	case USB_REQ_GET_DESCRIPTOR:		if (ctrl->bRequestType != USB_DIR_IN) {			goto unknown;		}		switch (w_value >> 8) {		case USB_DT_DEVICE:			value = min(w_length, (u16) sizeof(device_desc));			memcpy(req->buf, &device_desc, value);			break;		case USB_DT_CONFIG:			value = config_buf(gadget, req->buf,					w_value >> 8,					w_value & 0xff);			if (value >= 0) {				value = min(w_length, (u16)value);			}			break;		case USB_DT_STRING:			/* wIndex == language code.			 * this driver only handles one language, you can			 * add string tables for other languages, using			 * any UTF-8 characters			 */			value = usb_gadget_get_string(&stringtab,					w_value & 0xff, req->buf);			if (value >= 0) {				value = min(w_length, (u16)value);			}			break;		}		break;	/* currently two configs, two speeds */	case USB_REQ_SET_CONFIGURATION:		if (ctrl->bRequestType != 0) {			goto unknown;		}		if (gadget->a_hnp_support) {			DBG(dev, "HNP available\n");		} else if (gadget->a_alt_hnp_support) {			DBG(dev, "HNP needs a different root port\n");		} else {			VDBG(dev, "HNP inactive\n");		}		spin_lock(&dev->lock);		value = gmidi_set_config(dev, w_value, GFP_ATOMIC);		spin_unlock(&dev->lock);		break;	case USB_REQ_GET_CONFIGURATION:		if (ctrl->bRequestType != USB_DIR_IN) {			goto unknown;		}		*(u8 *)req->buf = dev->config;		value = min(w_length, (u16)1);		break;	/* until we add altsetting support, or other interfaces,	 * only 0/0 are possible.  pxa2xx only supports 0/0 (poorly)	 * and already killed pending endpoint I/O.	 */	case USB_REQ_SET_INTERFACE:		if (ctrl->bRequestType != USB_RECIP_INTERFACE) {			goto unknown;		}		spin_lock(&dev->lock);		if (dev->config && w_index < GMIDI_NUM_INTERFACES			&& w_value == 0)		{			u8 config = dev->config;			/* resets interface configuration, forgets about			 * previous transaction state (queued bufs, etc)			 * and re-inits endpoint state (toggle etc)			 * no response queued, just zero status == success.			 * if we had more than one interface we couldn't			 * use this "reset the config" shortcut.			 */			gmidi_reset_config(dev);			gmidi_set_config(dev, config, GFP_ATOMIC);			value = 0;		}		spin_unlock(&dev->lock);		break;	case USB_REQ_GET_INTERFACE:		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) {			goto unknown;		}		if (!dev->config) {			break;		}		if (w_index >= GMIDI_NUM_INTERFACES) {			value = -EDOM;			break;		}		*(u8 *)req->buf = 0;		value = min(w_length, (u16)1);		break;	default:unknown:		VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n",			ctrl->bRequestType, ctrl->bRequest,			w_value, w_index, w_length);	}	/* respond with data transfer before status phase? */	if (value >= 0) {		req->length = value;		req->zero = value < w_length;		value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);		if (value < 0) {			DBG(dev, "ep_queue --> %d\n", value);			req->status = 0;			gmidi_setup_complete(gadget->ep0, req);		}	}	/* device either stalls (value < 0) or reports success */	return value;}static void gmidi_disconnect(struct usb_gadget *gadget){	struct gmidi_device *dev = get_gadget_data(gadget);	unsigned long flags;	spin_lock_irqsave(&dev->lock, flags);	gmidi_reset_config(dev);	/* a more significant application might have some non-usb	 * activities to quiesce here, saving resources like power	 * or pushing the notification up a network stack.	 */	spin_unlock_irqrestore(&dev->lock, flags);	/* next we may get setup() calls to enumerate new connections;	 * or an unbind() during shutdown (including removing module).	 */}static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget){	struct gmidi_device *dev = get_gadget_data(gadget);	struct snd_card *card;	DBG(dev, "unbind\n");	card = dev->card;	dev->card = NULL;	if (card) {		snd_card_free(card);	}	/* we've already been disconnected ... no i/o is active */	if (dev->req) {		dev->req->length = USB_BUFSIZ;		free_ep_req(gadget->ep0, dev->req);	}	kfree(dev);	set_gadget_data(gadget, NULL);}static int gmidi_snd_free(struct snd_device *device){	return 0;}static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,					uint8_t p1, uint8_t p2, uint8_t p3){	unsigned length = req->length;	u8 *buf = (u8 *)req->buf + length;	buf[0] = p0;	buf[1] = p1;	buf[2] = p2;	buf[3] = p3;	req->length = length + 4;}/* * Converts MIDI commands to USB MIDI packets. */static void gmidi_transmit_byte(struct usb_request *req,				struct gmidi_in_port *port, uint8_t b){	uint8_t p0 = port->cable;	if (b >= 0xf8) {		gmidi_transmit_packet(req, p0 | 0x0f, b, 0, 0);	} else if (b >= 0xf0) {		switch (b) {		case 0xf0:			port->data[0] = b;			port->state = STATE_SYSEX_1;			break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -