brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · 49629d4 Raw
201 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Linux driver for TerraTec DMX 6Fire USB4 *5 * Device communications6 *7 * Author:	Torsten Schenk <torsten.schenk@zoho.com>8 * Created:	Jan 01, 20119 * Copyright:	(C) Torsten Schenk10 */11 12#include "comm.h"13#include "chip.h"14#include "midi.h"15 16enum {17	COMM_EP = 1,18	COMM_FPGA_EP = 219};20 21static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb,22		u8 *buffer, void *context, void(*handler)(struct urb *urb))23{24	usb_init_urb(urb);25	urb->transfer_buffer = buffer;26	urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP);27	urb->complete = handler;28	urb->context = context;29	urb->interval = 1;30	urb->dev = rt->chip->dev;31}32 33static void usb6fire_comm_receiver_handler(struct urb *urb)34{35	struct comm_runtime *rt = urb->context;36	struct midi_runtime *midi_rt = rt->chip->midi;37 38	if (!urb->status) {39		if (rt->receiver_buffer[0] == 0x10) /* midi in event */40			if (midi_rt)41				midi_rt->in_received(midi_rt,42						rt->receiver_buffer + 2,43						rt->receiver_buffer[1]);44	}45 46	if (!rt->chip->shutdown) {47		urb->status = 0;48		urb->actual_length = 0;49		if (usb_submit_urb(urb, GFP_ATOMIC) < 0)50			dev_warn(&urb->dev->dev,51					"comm data receiver aborted.\n");52	}53}54 55static void usb6fire_comm_init_buffer(u8 *buffer, u8 id, u8 request,56		u8 reg, u8 vl, u8 vh)57{58	buffer[0] = 0x01;59	buffer[2] = request;60	buffer[3] = id;61	switch (request) {62	case 0x02:63		buffer[1] = 0x05; /* length (starting at buffer[2]) */64		buffer[4] = reg;65		buffer[5] = vl;66		buffer[6] = vh;67		break;68 69	case 0x12:70		buffer[1] = 0x0b; /* length (starting at buffer[2]) */71		buffer[4] = 0x00;72		buffer[5] = 0x18;73		buffer[6] = 0x05;74		buffer[7] = 0x00;75		buffer[8] = 0x01;76		buffer[9] = 0x00;77		buffer[10] = 0x9e;78		buffer[11] = reg;79		buffer[12] = vl;80		break;81 82	case 0x20:83	case 0x21:84	case 0x22:85		buffer[1] = 0x04;86		buffer[4] = reg;87		buffer[5] = vl;88		break;89	}90}91 92static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev)93{94	int ret;95	int actual_len;96 97	ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP),98			buffer, buffer[1] + 2, &actual_len, 1000);99	if (ret < 0)100		return ret;101	else if (actual_len != buffer[1] + 2)102		return -EIO;103	return 0;104}105 106static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request,107		u8 reg, u8 value)108{109	u8 *buffer;110	int ret;111 112	/* 13: maximum length of message */113	buffer = kmalloc(13, GFP_KERNEL);114	if (!buffer)115		return -ENOMEM;116 117	usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);118	ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);119 120	kfree(buffer);121	return ret;122}123 124static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,125		u8 reg, u8 vl, u8 vh)126{127	u8 *buffer;128	int ret;129 130	/* 13: maximum length of message */131	buffer = kmalloc(13, GFP_KERNEL);132	if (!buffer)133		return -ENOMEM;134 135	usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);136	ret = usb6fire_comm_send_buffer(buffer, rt->chip->dev);137 138	kfree(buffer);139	return ret;140}141 142int usb6fire_comm_init(struct sfire_chip *chip)143{144	struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime),145			GFP_KERNEL);146	struct urb *urb;147	int ret;148 149	if (!rt)150		return -ENOMEM;151 152	rt->receiver_buffer = kzalloc(COMM_RECEIVER_BUFSIZE, GFP_KERNEL);153	if (!rt->receiver_buffer) {154		kfree(rt);155		return -ENOMEM;156	}157 158	urb = &rt->receiver;159	rt->serial = 1;160	rt->chip = chip;161	usb_init_urb(urb);162	rt->init_urb = usb6fire_comm_init_urb;163	rt->write8 = usb6fire_comm_write8;164	rt->write16 = usb6fire_comm_write16;165 166	/* submit an urb that receives communication data from device */167	urb->transfer_buffer = rt->receiver_buffer;168	urb->transfer_buffer_length = COMM_RECEIVER_BUFSIZE;169	urb->pipe = usb_rcvintpipe(chip->dev, COMM_EP);170	urb->dev = chip->dev;171	urb->complete = usb6fire_comm_receiver_handler;172	urb->context = rt;173	urb->interval = 1;174	ret = usb_submit_urb(urb, GFP_KERNEL);175	if (ret < 0) {176		kfree(rt->receiver_buffer);177		kfree(rt);178		dev_err(&chip->dev->dev, "cannot create comm data receiver.");179		return ret;180	}181	chip->comm = rt;182	return 0;183}184 185void usb6fire_comm_abort(struct sfire_chip *chip)186{187	struct comm_runtime *rt = chip->comm;188 189	if (rt)190		usb_poison_urb(&rt->receiver);191}192 193void usb6fire_comm_destroy(struct sfire_chip *chip)194{195	struct comm_runtime *rt = chip->comm;196 197	kfree(rt->receiver_buffer);198	kfree(rt);199	chip->comm = NULL;200}201