1 /*
2  * Linux driver for TerraTec DMX 6Fire USB
3  *
4  * Device communications
5  *
6  * Author:	Torsten Schenk <torsten.schenk@zoho.com>
7  * Created:	Jan 01, 2011
8  * Version:	0.3.0
9  * Copyright:	(C) Torsten Schenk
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  */
16 
17 #include "comm.h"
18 #include "chip.h"
19 #include "midi.h"
20 
21 enum {
22 	COMM_EP = 1,
23 	COMM_FPGA_EP = 2
24 };
25 
usb6fire_comm_init_urb(struct comm_runtime * rt,struct urb * urb,u8 * buffer,void * context,void (* handler)(struct urb * urb))26 static void usb6fire_comm_init_urb(struct comm_runtime *rt, struct urb *urb,
27 		u8 *buffer, void *context, void(*handler)(struct urb *urb))
28 {
29 	usb_init_urb(urb);
30 	urb->transfer_buffer = buffer;
31 	urb->pipe = usb_sndintpipe(rt->chip->dev, COMM_EP);
32 	urb->complete = handler;
33 	urb->context = context;
34 	urb->interval = 1;
35 	urb->dev = rt->chip->dev;
36 }
37 
usb6fire_comm_receiver_handler(struct urb * urb)38 static void usb6fire_comm_receiver_handler(struct urb *urb)
39 {
40 	struct comm_runtime *rt = urb->context;
41 	struct midi_runtime *midi_rt = rt->chip->midi;
42 
43 	if (!urb->status) {
44 		if (rt->receiver_buffer[0] == 0x10) /* midi in event */
45 			if (midi_rt)
46 				midi_rt->in_received(midi_rt,
47 						rt->receiver_buffer + 2,
48 						rt->receiver_buffer[1]);
49 	}
50 
51 	if (!rt->chip->shutdown) {
52 		urb->status = 0;
53 		urb->actual_length = 0;
54 		if (usb_submit_urb(urb, GFP_ATOMIC) < 0)
55 			snd_printk(KERN_WARNING PREFIX
56 					"comm data receiver aborted.\n");
57 	}
58 }
59 
usb6fire_comm_init_buffer(u8 * buffer,u8 id,u8 request,u8 reg,u8 vl,u8 vh)60 static void usb6fire_comm_init_buffer(u8 *buffer, u8 id, u8 request,
61 		u8 reg, u8 vl, u8 vh)
62 {
63 	buffer[0] = 0x01;
64 	buffer[2] = request;
65 	buffer[3] = id;
66 	switch (request) {
67 	case 0x02:
68 		buffer[1] = 0x05; /* length (starting at buffer[2]) */
69 		buffer[4] = reg;
70 		buffer[5] = vl;
71 		buffer[6] = vh;
72 		break;
73 
74 	case 0x12:
75 		buffer[1] = 0x0b; /* length (starting at buffer[2]) */
76 		buffer[4] = 0x00;
77 		buffer[5] = 0x18;
78 		buffer[6] = 0x05;
79 		buffer[7] = 0x00;
80 		buffer[8] = 0x01;
81 		buffer[9] = 0x00;
82 		buffer[10] = 0x9e;
83 		buffer[11] = reg;
84 		buffer[12] = vl;
85 		break;
86 
87 	case 0x20:
88 	case 0x21:
89 	case 0x22:
90 		buffer[1] = 0x04;
91 		buffer[4] = reg;
92 		buffer[5] = vl;
93 		break;
94 	}
95 }
96 
usb6fire_comm_send_buffer(u8 * buffer,struct usb_device * dev)97 static int usb6fire_comm_send_buffer(u8 *buffer, struct usb_device *dev)
98 {
99 	int ret;
100 	int actual_len;
101 
102 	ret = usb_interrupt_msg(dev, usb_sndintpipe(dev, COMM_EP),
103 			buffer, buffer[1] + 2, &actual_len, HZ);
104 	if (ret < 0)
105 		return ret;
106 	else if (actual_len != buffer[1] + 2)
107 		return -EIO;
108 	return 0;
109 }
110 
usb6fire_comm_write8(struct comm_runtime * rt,u8 request,u8 reg,u8 value)111 static int usb6fire_comm_write8(struct comm_runtime *rt, u8 request,
112 		u8 reg, u8 value)
113 {
114 	u8 buffer[13]; /* 13: maximum length of message */
115 
116 	usb6fire_comm_init_buffer(buffer, 0x00, request, reg, value, 0x00);
117 	return usb6fire_comm_send_buffer(buffer, rt->chip->dev);
118 }
119 
usb6fire_comm_write16(struct comm_runtime * rt,u8 request,u8 reg,u8 vl,u8 vh)120 static int usb6fire_comm_write16(struct comm_runtime *rt, u8 request,
121 		u8 reg, u8 vl, u8 vh)
122 {
123 	u8 buffer[13]; /* 13: maximum length of message */
124 
125 	usb6fire_comm_init_buffer(buffer, 0x00, request, reg, vl, vh);
126 	return usb6fire_comm_send_buffer(buffer, rt->chip->dev);
127 }
128 
usb6fire_comm_init(struct sfire_chip * chip)129 int __devinit usb6fire_comm_init(struct sfire_chip *chip)
130 {
131 	struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime),
132 			GFP_KERNEL);
133 	struct urb *urb = &rt->receiver;
134 	int ret;
135 
136 	if (!rt)
137 		return -ENOMEM;
138 
139 	rt->serial = 1;
140 	rt->chip = chip;
141 	usb_init_urb(urb);
142 	rt->init_urb = usb6fire_comm_init_urb;
143 	rt->write8 = usb6fire_comm_write8;
144 	rt->write16 = usb6fire_comm_write16;
145 
146 	/* submit an urb that receives communication data from device */
147 	urb->transfer_buffer = rt->receiver_buffer;
148 	urb->transfer_buffer_length = COMM_RECEIVER_BUFSIZE;
149 	urb->pipe = usb_rcvintpipe(chip->dev, COMM_EP);
150 	urb->dev = chip->dev;
151 	urb->complete = usb6fire_comm_receiver_handler;
152 	urb->context = rt;
153 	urb->interval = 1;
154 	ret = usb_submit_urb(urb, GFP_KERNEL);
155 	if (ret < 0) {
156 		kfree(rt);
157 		snd_printk(KERN_ERR PREFIX "cannot create comm data receiver.");
158 		return ret;
159 	}
160 	chip->comm = rt;
161 	return 0;
162 }
163 
usb6fire_comm_abort(struct sfire_chip * chip)164 void usb6fire_comm_abort(struct sfire_chip *chip)
165 {
166 	struct comm_runtime *rt = chip->comm;
167 
168 	if (rt)
169 		usb_poison_urb(&rt->receiver);
170 }
171 
usb6fire_comm_destroy(struct sfire_chip * chip)172 void usb6fire_comm_destroy(struct sfire_chip *chip)
173 {
174 	kfree(chip->comm);
175 	chip->comm = NULL;
176 }
177