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