Commit 72a474b8cdac7e316f5299b0edf2d82f86d92829
Committed by
Greg Kroah-Hartman
1 parent
ac399bc0f4
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Staging: frontier: Fix checkpatch.pl issue.
This is a patch to the alphatrack.c and tranzport.c that fixes up an error found by checkpatch.pl tool. Signed-off-by: Hitoshi Nakamori <hitoshi.nakamori@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Showing 2 changed files with 2 additions and 2 deletions Inline Diff
drivers/staging/frontier/alphatrack.c
1 | /* | 1 | /* |
2 | * Frontier Designs Alphatrack driver | 2 | * Frontier Designs Alphatrack driver |
3 | * | 3 | * |
4 | * Copyright (C) 2007 Michael Taht (m@taht.net) | 4 | * Copyright (C) 2007 Michael Taht (m@taht.net) |
5 | * | 5 | * |
6 | * Based on the usbled driver and ldusb drivers by | 6 | * Based on the usbled driver and ldusb drivers by |
7 | * | 7 | * |
8 | * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com) | 8 | * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com) |
9 | * Copyright (C) 2005 Michael Hund <mhund@ld-didactic.de> | 9 | * Copyright (C) 2005 Michael Hund <mhund@ld-didactic.de> |
10 | * | 10 | * |
11 | * The ldusb driver was, in turn, derived from Lego USB Tower driver | 11 | * The ldusb driver was, in turn, derived from Lego USB Tower driver |
12 | * Copyright (C) 2003 David Glance <advidgsf@sourceforge.net> | 12 | * Copyright (C) 2003 David Glance <advidgsf@sourceforge.net> |
13 | * 2001-2004 Juergen Stuber <starblue@users.sourceforge.net> | 13 | * 2001-2004 Juergen Stuber <starblue@users.sourceforge.net> |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or | 15 | * This program is free software; you can redistribute it and/or |
16 | * modify it under the terms of the GNU General Public License as | 16 | * modify it under the terms of the GNU General Public License as |
17 | * published by the Free Software Foundation, version 2. | 17 | * published by the Free Software Foundation, version 2. |
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * This driver uses a ring buffer for time critical reading of | 22 | * This driver uses a ring buffer for time critical reading of |
23 | * interrupt in reports and provides read and write methods for | 23 | * interrupt in reports and provides read and write methods for |
24 | * raw interrupt reports. | 24 | * raw interrupt reports. |
25 | */ | 25 | */ |
26 | 26 | ||
27 | /* Note: this currently uses a dumb ringbuffer for reads and writes. | 27 | /* Note: this currently uses a dumb ringbuffer for reads and writes. |
28 | * A more optimal driver would cache and kill off outstanding urbs that are | 28 | * A more optimal driver would cache and kill off outstanding urbs that are |
29 | * now invalid, and ignore ones that already were in the queue but valid | 29 | * now invalid, and ignore ones that already were in the queue but valid |
30 | * as we only have 30 commands for the alphatrack. In particular this is | 30 | * as we only have 30 commands for the alphatrack. In particular this is |
31 | * key for getting lights to flash in time as otherwise many commands | 31 | * key for getting lights to flash in time as otherwise many commands |
32 | * can be buffered up before the light change makes it to the interface. | 32 | * can be buffered up before the light change makes it to the interface. |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/kernel.h> | 35 | #include <linux/kernel.h> |
36 | #include <linux/errno.h> | 36 | #include <linux/errno.h> |
37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
40 | #include <linux/kobject.h> | 40 | #include <linux/kobject.h> |
41 | #include <linux/mutex.h> | 41 | #include <linux/mutex.h> |
42 | 42 | ||
43 | #include <linux/uaccess.h> | 43 | #include <linux/uaccess.h> |
44 | #include <linux/input.h> | 44 | #include <linux/input.h> |
45 | #include <linux/usb.h> | 45 | #include <linux/usb.h> |
46 | #include <linux/poll.h> | 46 | #include <linux/poll.h> |
47 | 47 | ||
48 | #include "alphatrack.h" | 48 | #include "alphatrack.h" |
49 | 49 | ||
50 | #define VENDOR_ID 0x165b | 50 | #define VENDOR_ID 0x165b |
51 | #define PRODUCT_ID 0xfad1 | 51 | #define PRODUCT_ID 0xfad1 |
52 | 52 | ||
53 | #ifdef CONFIG_USB_DYNAMIC_MINORS | 53 | #ifdef CONFIG_USB_DYNAMIC_MINORS |
54 | #define USB_ALPHATRACK_MINOR_BASE 0 | 54 | #define USB_ALPHATRACK_MINOR_BASE 0 |
55 | #else | 55 | #else |
56 | /* FIXME 176 - is another driver's minor - apply for that */ | 56 | /* FIXME 176 - is another driver's minor - apply for that */ |
57 | #define USB_ALPHATRACK_MINOR_BASE 176 | 57 | #define USB_ALPHATRACK_MINOR_BASE 176 |
58 | #endif | 58 | #endif |
59 | 59 | ||
60 | /* table of devices that work with this driver */ | 60 | /* table of devices that work with this driver */ |
61 | static const struct usb_device_id usb_alphatrack_table[] = { | 61 | static const struct usb_device_id usb_alphatrack_table[] = { |
62 | {USB_DEVICE(VENDOR_ID, PRODUCT_ID)}, | 62 | {USB_DEVICE(VENDOR_ID, PRODUCT_ID)}, |
63 | {} /* Terminating entry */ | 63 | {} /* Terminating entry */ |
64 | }; | 64 | }; |
65 | 65 | ||
66 | MODULE_DEVICE_TABLE(usb, usb_alphatrack_table); | 66 | MODULE_DEVICE_TABLE(usb, usb_alphatrack_table); |
67 | MODULE_VERSION("0.41"); | 67 | MODULE_VERSION("0.41"); |
68 | MODULE_AUTHOR("Mike Taht <m@taht.net>"); | 68 | MODULE_AUTHOR("Mike Taht <m@taht.net>"); |
69 | MODULE_DESCRIPTION("Alphatrack USB Driver"); | 69 | MODULE_DESCRIPTION("Alphatrack USB Driver"); |
70 | MODULE_LICENSE("GPL"); | 70 | MODULE_LICENSE("GPL"); |
71 | MODULE_SUPPORTED_DEVICE("Frontier Designs Alphatrack Control Surface"); | 71 | MODULE_SUPPORTED_DEVICE("Frontier Designs Alphatrack Control Surface"); |
72 | 72 | ||
73 | /* These aren't done yet */ | 73 | /* These aren't done yet */ |
74 | 74 | ||
75 | #define SUPPRESS_EXTRA_ONLINE_EVENTS 0 | 75 | #define SUPPRESS_EXTRA_ONLINE_EVENTS 0 |
76 | #define BUFFERED_WRITES 0 | 76 | #define BUFFERED_WRITES 0 |
77 | #define SUPPRESS_EXTRA_OFFLINE_EVENTS 0 | 77 | #define SUPPRESS_EXTRA_OFFLINE_EVENTS 0 |
78 | #define COMPRESS_FADER_EVENTS 0 | 78 | #define COMPRESS_FADER_EVENTS 0 |
79 | 79 | ||
80 | #define BUFFERED_READS 1 | 80 | #define BUFFERED_READS 1 |
81 | #define RING_BUFFER_SIZE 512 | 81 | #define RING_BUFFER_SIZE 512 |
82 | #define WRITE_BUFFER_SIZE 34 | 82 | #define WRITE_BUFFER_SIZE 34 |
83 | #define ALPHATRACK_USB_TIMEOUT 10 | 83 | #define ALPHATRACK_USB_TIMEOUT 10 |
84 | #define OUTPUT_CMD_SIZE 8 | 84 | #define OUTPUT_CMD_SIZE 8 |
85 | #define INPUT_CMD_SIZE 12 | 85 | #define INPUT_CMD_SIZE 12 |
86 | #define ALPHATRACK_DEBUG 0 | 86 | #define ALPHATRACK_DEBUG 0 |
87 | 87 | ||
88 | static int debug = ALPHATRACK_DEBUG; | 88 | static int debug = ALPHATRACK_DEBUG; |
89 | 89 | ||
90 | /* Use our own dbg macro */ | 90 | /* Use our own dbg macro */ |
91 | #define dbg_info(dev, format, arg...) do \ | 91 | #define dbg_info(dev, format, arg...) do \ |
92 | { if (debug) dev_info(dev , format , ## arg); } while (0) | 92 | { if (debug) dev_info(dev , format , ## arg); } while (0) |
93 | 93 | ||
94 | #define alphatrack_ocmd_info(dev, cmd, format, arg...) | 94 | #define alphatrack_ocmd_info(dev, cmd, format, arg...) |
95 | 95 | ||
96 | #define alphatrack_icmd_info(dev, cmd, format, arg...) | 96 | #define alphatrack_icmd_info(dev, cmd, format, arg...) |
97 | 97 | ||
98 | /* Module parameters */ | 98 | /* Module parameters */ |
99 | 99 | ||
100 | module_param(debug, int, S_IRUGO | S_IWUSR); | 100 | module_param(debug, int, S_IRUGO | S_IWUSR); |
101 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | 101 | MODULE_PARM_DESC(debug, "Debug enabled or not"); |
102 | 102 | ||
103 | /* All interrupt in transfers are collected in a ring buffer to | 103 | /* All interrupt in transfers are collected in a ring buffer to |
104 | * avoid racing conditions and get better performance of the driver. | 104 | * avoid racing conditions and get better performance of the driver. |
105 | */ | 105 | */ |
106 | 106 | ||
107 | static int ring_buffer_size = RING_BUFFER_SIZE; | 107 | static int ring_buffer_size = RING_BUFFER_SIZE; |
108 | 108 | ||
109 | module_param(ring_buffer_size, int, S_IRUGO); | 109 | module_param(ring_buffer_size, int, S_IRUGO); |
110 | MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size"); | 110 | MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size"); |
111 | 111 | ||
112 | /* The write_buffer can one day contain more than one interrupt out transfer. | 112 | /* The write_buffer can one day contain more than one interrupt out transfer. |
113 | */ | 113 | */ |
114 | 114 | ||
115 | static int write_buffer_size = WRITE_BUFFER_SIZE; | 115 | static int write_buffer_size = WRITE_BUFFER_SIZE; |
116 | module_param(write_buffer_size, int, S_IRUGO); | 116 | module_param(write_buffer_size, int, S_IRUGO); |
117 | MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); | 117 | MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); |
118 | 118 | ||
119 | /* | 119 | /* |
120 | * Increase the interval for debugging purposes. | 120 | * Increase the interval for debugging purposes. |
121 | * or set to 1 to use the standard interval from the endpoint descriptors. | 121 | * or set to 1 to use the standard interval from the endpoint descriptors. |
122 | */ | 122 | */ |
123 | 123 | ||
124 | static int min_interrupt_in_interval = ALPHATRACK_USB_TIMEOUT; | 124 | static int min_interrupt_in_interval = ALPHATRACK_USB_TIMEOUT; |
125 | module_param(min_interrupt_in_interval, int, 0); | 125 | module_param(min_interrupt_in_interval, int, 0); |
126 | MODULE_PARM_DESC(min_interrupt_in_interval, | 126 | MODULE_PARM_DESC(min_interrupt_in_interval, |
127 | "Minimum interrupt in interval in ms"); | 127 | "Minimum interrupt in interval in ms"); |
128 | 128 | ||
129 | static int min_interrupt_out_interval = ALPHATRACK_USB_TIMEOUT; | 129 | static int min_interrupt_out_interval = ALPHATRACK_USB_TIMEOUT; |
130 | module_param(min_interrupt_out_interval, int, 0); | 130 | module_param(min_interrupt_out_interval, int, 0); |
131 | MODULE_PARM_DESC(min_interrupt_out_interval, | 131 | MODULE_PARM_DESC(min_interrupt_out_interval, |
132 | "Minimum interrupt out interval in ms"); | 132 | "Minimum interrupt out interval in ms"); |
133 | 133 | ||
134 | /* Structure to hold all of our device specific stuff */ | 134 | /* Structure to hold all of our device specific stuff */ |
135 | 135 | ||
136 | struct usb_alphatrack { | 136 | struct usb_alphatrack { |
137 | struct mutex mtx; /* locks this structure */ | 137 | struct mutex mtx; /* locks this structure */ |
138 | struct usb_interface *intf; /* save off the usb interface pointer */ | 138 | struct usb_interface *intf; /* save off the usb interface pointer */ |
139 | int open_count; /* number of times this port has been opened */ | 139 | int open_count; /* number of times this port has been opened */ |
140 | 140 | ||
141 | /* make gcc happy */ | 141 | /* make gcc happy */ |
142 | struct alphatrack_icmd (*ring_buffer)[RING_BUFFER_SIZE]; | 142 | struct alphatrack_icmd (*ring_buffer)[RING_BUFFER_SIZE]; |
143 | struct alphatrack_ocmd (*write_buffer)[WRITE_BUFFER_SIZE]; | 143 | struct alphatrack_ocmd (*write_buffer)[WRITE_BUFFER_SIZE]; |
144 | unsigned int ring_head; | 144 | unsigned int ring_head; |
145 | unsigned int ring_tail; | 145 | unsigned int ring_tail; |
146 | 146 | ||
147 | wait_queue_head_t read_wait; | 147 | wait_queue_head_t read_wait; |
148 | wait_queue_head_t write_wait; | 148 | wait_queue_head_t write_wait; |
149 | 149 | ||
150 | unsigned char *interrupt_in_buffer; | 150 | unsigned char *interrupt_in_buffer; |
151 | unsigned char *oldi_buffer; | 151 | unsigned char *oldi_buffer; |
152 | struct usb_endpoint_descriptor *interrupt_in_endpoint; | 152 | struct usb_endpoint_descriptor *interrupt_in_endpoint; |
153 | struct urb *interrupt_in_urb; | 153 | struct urb *interrupt_in_urb; |
154 | int interrupt_in_interval; | 154 | int interrupt_in_interval; |
155 | size_t interrupt_in_endpoint_size; | 155 | size_t interrupt_in_endpoint_size; |
156 | int interrupt_in_running; | 156 | int interrupt_in_running; |
157 | int interrupt_in_done; | 157 | int interrupt_in_done; |
158 | 158 | ||
159 | char *interrupt_out_buffer; | 159 | char *interrupt_out_buffer; |
160 | struct usb_endpoint_descriptor *interrupt_out_endpoint; | 160 | struct usb_endpoint_descriptor *interrupt_out_endpoint; |
161 | struct urb *interrupt_out_urb; | 161 | struct urb *interrupt_out_urb; |
162 | int interrupt_out_interval; | 162 | int interrupt_out_interval; |
163 | size_t interrupt_out_endpoint_size; | 163 | size_t interrupt_out_endpoint_size; |
164 | int interrupt_out_busy; | 164 | int interrupt_out_busy; |
165 | 165 | ||
166 | atomic_t writes_pending; | 166 | atomic_t writes_pending; |
167 | int event; /* alternate interface to events */ | 167 | int event; /* alternate interface to events */ |
168 | int fader; /* 10 bits */ | 168 | int fader; /* 10 bits */ |
169 | int lights; /* 23 bits */ | 169 | int lights; /* 23 bits */ |
170 | unsigned char dump_state; /* 0 if disabled 1 if enabled */ | 170 | unsigned char dump_state; /* 0 if disabled 1 if enabled */ |
171 | unsigned char enable; /* 0 if disabled 1 if enabled */ | 171 | unsigned char enable; /* 0 if disabled 1 if enabled */ |
172 | unsigned char offline; /* if the device is out of range or asleep */ | 172 | unsigned char offline; /* if the device is out of range or asleep */ |
173 | unsigned char verbose; /* be verbose in error reporting */ | 173 | unsigned char verbose; /* be verbose in error reporting */ |
174 | unsigned char last_cmd[OUTPUT_CMD_SIZE]; | 174 | unsigned char last_cmd[OUTPUT_CMD_SIZE]; |
175 | unsigned char screen[32]; | 175 | unsigned char screen[32]; |
176 | }; | 176 | }; |
177 | 177 | ||
178 | /* prevent races between open() and disconnect() */ | 178 | /* prevent races between open() and disconnect() */ |
179 | static DEFINE_MUTEX(disconnect_mutex); | 179 | static DEFINE_MUTEX(disconnect_mutex); |
180 | 180 | ||
181 | /* forward declaration */ | 181 | /* forward declaration */ |
182 | 182 | ||
183 | static struct usb_driver usb_alphatrack_driver; | 183 | static struct usb_driver usb_alphatrack_driver; |
184 | 184 | ||
185 | /** | 185 | /** |
186 | * usb_alphatrack_abort_transfers | 186 | * usb_alphatrack_abort_transfers |
187 | * aborts transfers and frees associated data structures | 187 | * aborts transfers and frees associated data structures |
188 | */ | 188 | */ |
189 | static void usb_alphatrack_abort_transfers(struct usb_alphatrack *dev) | 189 | static void usb_alphatrack_abort_transfers(struct usb_alphatrack *dev) |
190 | { | 190 | { |
191 | /* shutdown transfer */ | 191 | /* shutdown transfer */ |
192 | if (dev->interrupt_in_running) { | 192 | if (dev->interrupt_in_running) { |
193 | dev->interrupt_in_running = 0; | 193 | dev->interrupt_in_running = 0; |
194 | if (dev->intf) | 194 | if (dev->intf) |
195 | usb_kill_urb(dev->interrupt_in_urb); | 195 | usb_kill_urb(dev->interrupt_in_urb); |
196 | } | 196 | } |
197 | if (dev->interrupt_out_busy) | 197 | if (dev->interrupt_out_busy) |
198 | if (dev->intf) | 198 | if (dev->intf) |
199 | usb_kill_urb(dev->interrupt_out_urb); | 199 | usb_kill_urb(dev->interrupt_out_urb); |
200 | } | 200 | } |
201 | 201 | ||
202 | /** | 202 | /** |
203 | * usb_alphatrack_delete | 203 | * usb_alphatrack_delete |
204 | */ | 204 | */ |
205 | static void usb_alphatrack_delete(struct usb_alphatrack *dev) | 205 | static void usb_alphatrack_delete(struct usb_alphatrack *dev) |
206 | { | 206 | { |
207 | usb_alphatrack_abort_transfers(dev); | 207 | usb_alphatrack_abort_transfers(dev); |
208 | usb_free_urb(dev->interrupt_in_urb); | 208 | usb_free_urb(dev->interrupt_in_urb); |
209 | usb_free_urb(dev->interrupt_out_urb); | 209 | usb_free_urb(dev->interrupt_out_urb); |
210 | kfree(dev->ring_buffer); | 210 | kfree(dev->ring_buffer); |
211 | kfree(dev->interrupt_in_buffer); | 211 | kfree(dev->interrupt_in_buffer); |
212 | kfree(dev->interrupt_out_buffer); | 212 | kfree(dev->interrupt_out_buffer); |
213 | kfree(dev); /* fixme oldi_buffer */ | 213 | kfree(dev); /* fixme oldi_buffer */ |
214 | } | 214 | } |
215 | 215 | ||
216 | /** | 216 | /** |
217 | * usb_alphatrack_interrupt_in_callback | 217 | * usb_alphatrack_interrupt_in_callback |
218 | */ | 218 | */ |
219 | 219 | ||
220 | static void usb_alphatrack_interrupt_in_callback(struct urb *urb) | 220 | static void usb_alphatrack_interrupt_in_callback(struct urb *urb) |
221 | { | 221 | { |
222 | struct usb_alphatrack *dev = urb->context; | 222 | struct usb_alphatrack *dev = urb->context; |
223 | unsigned int next_ring_head; | 223 | unsigned int next_ring_head; |
224 | int retval = -1; | 224 | int retval = -1; |
225 | 225 | ||
226 | if (urb->status) { | 226 | if (urb->status) { |
227 | if (urb->status == -ENOENT || | 227 | if (urb->status == -ENOENT || |
228 | urb->status == -ECONNRESET || urb->status == -ESHUTDOWN) { | 228 | urb->status == -ECONNRESET || urb->status == -ESHUTDOWN) { |
229 | goto exit; | 229 | goto exit; |
230 | } else { | 230 | } else { |
231 | dbg_info(&dev->intf->dev, | 231 | dbg_info(&dev->intf->dev, |
232 | "%s: nonzero status received: %d\n", __func__, | 232 | "%s: nonzero status received: %d\n", __func__, |
233 | urb->status); | 233 | urb->status); |
234 | goto resubmit; /* maybe we can recover */ | 234 | goto resubmit; /* maybe we can recover */ |
235 | } | 235 | } |
236 | } | 236 | } |
237 | 237 | ||
238 | if (urb->actual_length != INPUT_CMD_SIZE) { | 238 | if (urb->actual_length != INPUT_CMD_SIZE) { |
239 | dev_warn(&dev->intf->dev, | 239 | dev_warn(&dev->intf->dev, |
240 | "Urb length was %d bytes!!" | 240 | "Urb length was %d bytes!!" |
241 | "Do something intelligent\n", urb->actual_length); | 241 | "Do something intelligent\n", urb->actual_length); |
242 | } else { | 242 | } else { |
243 | alphatrack_ocmd_info(&dev->intf->dev, | 243 | alphatrack_ocmd_info(&dev->intf->dev, |
244 | &(*dev->ring_buffer)[dev->ring_tail].cmd, | 244 | &(*dev->ring_buffer)[dev->ring_tail].cmd, |
245 | "%s", "bla"); | 245 | "%s", "bla"); |
246 | if (memcmp | 246 | if (memcmp |
247 | (dev->interrupt_in_buffer, dev->oldi_buffer, | 247 | (dev->interrupt_in_buffer, dev->oldi_buffer, |
248 | INPUT_CMD_SIZE) == 0) { | 248 | INPUT_CMD_SIZE) == 0) { |
249 | goto resubmit; | 249 | goto resubmit; |
250 | } | 250 | } |
251 | memcpy(dev->oldi_buffer, dev->interrupt_in_buffer, | 251 | memcpy(dev->oldi_buffer, dev->interrupt_in_buffer, |
252 | INPUT_CMD_SIZE); | 252 | INPUT_CMD_SIZE); |
253 | 253 | ||
254 | #if SUPPRESS_EXTRA_OFFLINE_EVENTS | 254 | #if SUPPRESS_EXTRA_OFFLINE_EVENTS |
255 | if (dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) | 255 | if (dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) |
256 | goto resubmit; | 256 | goto resubmit; |
257 | if (dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { | 257 | if (dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { |
258 | dev->offline = 2; | 258 | dev->offline = 2; |
259 | goto resubmit; | 259 | goto resubmit; |
260 | } | 260 | } |
261 | /* Always pass one offline event up the stack */ | 261 | /* Always pass one offline event up the stack */ |
262 | if (dev->offline > 0 && dev->interrupt_in_buffer[1] != 0xff) | 262 | if (dev->offline > 0 && dev->interrupt_in_buffer[1] != 0xff) |
263 | dev->offline = 0; | 263 | dev->offline = 0; |
264 | if (dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) | 264 | if (dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) |
265 | dev->offline = 1; | 265 | dev->offline = 1; |
266 | #endif | 266 | #endif |
267 | dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", | 267 | dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", |
268 | __func__, dev->ring_head, dev->ring_tail); | 268 | __func__, dev->ring_head, dev->ring_tail); |
269 | next_ring_head = (dev->ring_head + 1) % ring_buffer_size; | 269 | next_ring_head = (dev->ring_head + 1) % ring_buffer_size; |
270 | 270 | ||
271 | if (next_ring_head != dev->ring_tail) { | 271 | if (next_ring_head != dev->ring_tail) { |
272 | memcpy(&((*dev->ring_buffer)[dev->ring_head]), | 272 | memcpy(&((*dev->ring_buffer)[dev->ring_head]), |
273 | dev->interrupt_in_buffer, urb->actual_length); | 273 | dev->interrupt_in_buffer, urb->actual_length); |
274 | dev->ring_head = next_ring_head; | 274 | dev->ring_head = next_ring_head; |
275 | retval = 0; | 275 | retval = 0; |
276 | memset(dev->interrupt_in_buffer, 0, urb->actual_length); | 276 | memset(dev->interrupt_in_buffer, 0, urb->actual_length); |
277 | } else { | 277 | } else { |
278 | dev_warn(&dev->intf->dev, | 278 | dev_warn(&dev->intf->dev, |
279 | "Ring buffer overflow, %d bytes dropped\n", | 279 | "Ring buffer overflow, %d bytes dropped\n", |
280 | urb->actual_length); | 280 | urb->actual_length); |
281 | memset(dev->interrupt_in_buffer, 0, urb->actual_length); | 281 | memset(dev->interrupt_in_buffer, 0, urb->actual_length); |
282 | } | 282 | } |
283 | } | 283 | } |
284 | 284 | ||
285 | resubmit: | 285 | resubmit: |
286 | /* resubmit if we're still running */ | 286 | /* resubmit if we're still running */ |
287 | if (dev->interrupt_in_running && dev->intf) { | 287 | if (dev->interrupt_in_running && dev->intf) { |
288 | retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); | 288 | retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); |
289 | if (retval) | 289 | if (retval) |
290 | dev_err(&dev->intf->dev, | 290 | dev_err(&dev->intf->dev, |
291 | "usb_submit_urb failed (%d)\n", retval); | 291 | "usb_submit_urb failed (%d)\n", retval); |
292 | } | 292 | } |
293 | 293 | ||
294 | exit: | 294 | exit: |
295 | dev->interrupt_in_done = 1; | 295 | dev->interrupt_in_done = 1; |
296 | wake_up_interruptible(&dev->read_wait); | 296 | wake_up_interruptible(&dev->read_wait); |
297 | } | 297 | } |
298 | 298 | ||
299 | /** | 299 | /** |
300 | * usb_alphatrack_interrupt_out_callback | 300 | * usb_alphatrack_interrupt_out_callback |
301 | */ | 301 | */ |
302 | static void usb_alphatrack_interrupt_out_callback(struct urb *urb) | 302 | static void usb_alphatrack_interrupt_out_callback(struct urb *urb) |
303 | { | 303 | { |
304 | struct usb_alphatrack *dev = urb->context; | 304 | struct usb_alphatrack *dev = urb->context; |
305 | 305 | ||
306 | /* sync/async unlink faults aren't errors */ | 306 | /* sync/async unlink faults aren't errors */ |
307 | if (urb->status && !(urb->status == -ENOENT || | 307 | if (urb->status && !(urb->status == -ENOENT || |
308 | urb->status == -ECONNRESET || | 308 | urb->status == -ECONNRESET || |
309 | urb->status == -ESHUTDOWN)) | 309 | urb->status == -ESHUTDOWN)) |
310 | dbg_info(&dev->intf->dev, | 310 | dbg_info(&dev->intf->dev, |
311 | "%s - nonzero write interrupt status received: %d\n", | 311 | "%s - nonzero write interrupt status received: %d\n", |
312 | __func__, urb->status); | 312 | __func__, urb->status); |
313 | atomic_dec(&dev->writes_pending); | 313 | atomic_dec(&dev->writes_pending); |
314 | dev->interrupt_out_busy = 0; | 314 | dev->interrupt_out_busy = 0; |
315 | wake_up_interruptible(&dev->write_wait); | 315 | wake_up_interruptible(&dev->write_wait); |
316 | } | 316 | } |
317 | 317 | ||
318 | /** | 318 | /** |
319 | * usb_alphatrack_open | 319 | * usb_alphatrack_open |
320 | */ | 320 | */ |
321 | static int usb_alphatrack_open(struct inode *inode, struct file *file) | 321 | static int usb_alphatrack_open(struct inode *inode, struct file *file) |
322 | { | 322 | { |
323 | struct usb_alphatrack *dev; | 323 | struct usb_alphatrack *dev; |
324 | int subminor; | 324 | int subminor; |
325 | int retval = 0; | 325 | int retval = 0; |
326 | struct usb_interface *interface; | 326 | struct usb_interface *interface; |
327 | 327 | ||
328 | nonseekable_open(inode, file); | 328 | nonseekable_open(inode, file); |
329 | subminor = iminor(inode); | 329 | subminor = iminor(inode); |
330 | 330 | ||
331 | mutex_lock(&disconnect_mutex); | 331 | mutex_lock(&disconnect_mutex); |
332 | 332 | ||
333 | interface = usb_find_interface(&usb_alphatrack_driver, subminor); | 333 | interface = usb_find_interface(&usb_alphatrack_driver, subminor); |
334 | 334 | ||
335 | if (!interface) { | 335 | if (!interface) { |
336 | err("%s - error, can't find device for minor %d\n", | 336 | err("%s - error, can't find device for minor %d\n", |
337 | __func__, subminor); | 337 | __func__, subminor); |
338 | retval = -ENODEV; | 338 | retval = -ENODEV; |
339 | goto unlock_disconnect_exit; | 339 | goto unlock_disconnect_exit; |
340 | } | 340 | } |
341 | 341 | ||
342 | dev = usb_get_intfdata(interface); | 342 | dev = usb_get_intfdata(interface); |
343 | 343 | ||
344 | if (!dev) { | 344 | if (!dev) { |
345 | retval = -ENODEV; | 345 | retval = -ENODEV; |
346 | goto unlock_disconnect_exit; | 346 | goto unlock_disconnect_exit; |
347 | } | 347 | } |
348 | 348 | ||
349 | /* lock this device */ | 349 | /* lock this device */ |
350 | if (mutex_lock_interruptible(&dev->mtx)) { | 350 | if (mutex_lock_interruptible(&dev->mtx)) { |
351 | retval = -ERESTARTSYS; | 351 | retval = -ERESTARTSYS; |
352 | goto unlock_disconnect_exit; | 352 | goto unlock_disconnect_exit; |
353 | } | 353 | } |
354 | 354 | ||
355 | /* allow opening only once */ | 355 | /* allow opening only once */ |
356 | if (dev->open_count) { | 356 | if (dev->open_count) { |
357 | retval = -EBUSY; | 357 | retval = -EBUSY; |
358 | goto unlock_exit; | 358 | goto unlock_exit; |
359 | } | 359 | } |
360 | dev->open_count = 1; | 360 | dev->open_count = 1; |
361 | 361 | ||
362 | /* initialize in direction */ | 362 | /* initialize in direction */ |
363 | dev->ring_head = 0; | 363 | dev->ring_head = 0; |
364 | dev->ring_tail = 0; | 364 | dev->ring_tail = 0; |
365 | usb_fill_int_urb(dev->interrupt_in_urb, | 365 | usb_fill_int_urb(dev->interrupt_in_urb, |
366 | interface_to_usbdev(interface), | 366 | interface_to_usbdev(interface), |
367 | usb_rcvintpipe(interface_to_usbdev(interface), | 367 | usb_rcvintpipe(interface_to_usbdev(interface), |
368 | dev->interrupt_in_endpoint-> | 368 | dev->interrupt_in_endpoint-> |
369 | bEndpointAddress), | 369 | bEndpointAddress), |
370 | dev->interrupt_in_buffer, | 370 | dev->interrupt_in_buffer, |
371 | dev->interrupt_in_endpoint_size, | 371 | dev->interrupt_in_endpoint_size, |
372 | usb_alphatrack_interrupt_in_callback, dev, | 372 | usb_alphatrack_interrupt_in_callback, dev, |
373 | dev->interrupt_in_interval); | 373 | dev->interrupt_in_interval); |
374 | 374 | ||
375 | dev->interrupt_in_running = 1; | 375 | dev->interrupt_in_running = 1; |
376 | dev->interrupt_in_done = 0; | 376 | dev->interrupt_in_done = 0; |
377 | dev->enable = 1; | 377 | dev->enable = 1; |
378 | dev->offline = 0; | 378 | dev->offline = 0; |
379 | 379 | ||
380 | retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); | 380 | retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); |
381 | if (retval) { | 381 | if (retval) { |
382 | dev_err(&interface->dev, | 382 | dev_err(&interface->dev, |
383 | "Couldn't submit interrupt_in_urb %d\n", retval); | 383 | "Couldn't submit interrupt_in_urb %d\n", retval); |
384 | dev->interrupt_in_running = 0; | 384 | dev->interrupt_in_running = 0; |
385 | dev->open_count = 0; | 385 | dev->open_count = 0; |
386 | goto unlock_exit; | 386 | goto unlock_exit; |
387 | } | 387 | } |
388 | 388 | ||
389 | /* save device in the file's private structure */ | 389 | /* save device in the file's private structure */ |
390 | file->private_data = dev; | 390 | file->private_data = dev; |
391 | 391 | ||
392 | unlock_exit: | 392 | unlock_exit: |
393 | mutex_unlock(&dev->mtx); | 393 | mutex_unlock(&dev->mtx); |
394 | 394 | ||
395 | unlock_disconnect_exit: | 395 | unlock_disconnect_exit: |
396 | mutex_unlock(&disconnect_mutex); | 396 | mutex_unlock(&disconnect_mutex); |
397 | 397 | ||
398 | return retval; | 398 | return retval; |
399 | } | 399 | } |
400 | 400 | ||
401 | /** | 401 | /** |
402 | * usb_alphatrack_release | 402 | * usb_alphatrack_release |
403 | */ | 403 | */ |
404 | static int usb_alphatrack_release(struct inode *inode, struct file *file) | 404 | static int usb_alphatrack_release(struct inode *inode, struct file *file) |
405 | { | 405 | { |
406 | struct usb_alphatrack *dev; | 406 | struct usb_alphatrack *dev; |
407 | int retval = 0; | 407 | int retval = 0; |
408 | 408 | ||
409 | dev = file->private_data; | 409 | dev = file->private_data; |
410 | 410 | ||
411 | if (dev == NULL) { | 411 | if (dev == NULL) { |
412 | retval = -ENODEV; | 412 | retval = -ENODEV; |
413 | goto exit; | 413 | goto exit; |
414 | } | 414 | } |
415 | 415 | ||
416 | if (mutex_lock_interruptible(&dev->mtx)) { | 416 | if (mutex_lock_interruptible(&dev->mtx)) { |
417 | retval = -ERESTARTSYS; | 417 | retval = -ERESTARTSYS; |
418 | goto exit; | 418 | goto exit; |
419 | } | 419 | } |
420 | 420 | ||
421 | if (dev->open_count != 1) { | 421 | if (dev->open_count != 1) { |
422 | retval = -ENODEV; | 422 | retval = -ENODEV; |
423 | goto unlock_exit; | 423 | goto unlock_exit; |
424 | } | 424 | } |
425 | 425 | ||
426 | if (dev->intf == NULL) { | 426 | if (dev->intf == NULL) { |
427 | /* the device was unplugged before the file was released */ | 427 | /* the device was unplugged before the file was released */ |
428 | mutex_unlock(&dev->mtx); | 428 | mutex_unlock(&dev->mtx); |
429 | /* unlock here as usb_alphatrack_delete frees dev */ | 429 | /* unlock here as usb_alphatrack_delete frees dev */ |
430 | usb_alphatrack_delete(dev); | 430 | usb_alphatrack_delete(dev); |
431 | retval = -ENODEV; | 431 | retval = -ENODEV; |
432 | goto exit; | 432 | goto exit; |
433 | } | 433 | } |
434 | 434 | ||
435 | /* wait until write transfer is finished */ | 435 | /* wait until write transfer is finished */ |
436 | if (dev->interrupt_out_busy) | 436 | if (dev->interrupt_out_busy) |
437 | wait_event_interruptible_timeout(dev->write_wait, | 437 | wait_event_interruptible_timeout(dev->write_wait, |
438 | !dev->interrupt_out_busy, | 438 | !dev->interrupt_out_busy, |
439 | 2 * HZ); | 439 | 2 * HZ); |
440 | usb_alphatrack_abort_transfers(dev); | 440 | usb_alphatrack_abort_transfers(dev); |
441 | dev->open_count = 0; | 441 | dev->open_count = 0; |
442 | 442 | ||
443 | unlock_exit: | 443 | unlock_exit: |
444 | mutex_unlock(&dev->mtx); | 444 | mutex_unlock(&dev->mtx); |
445 | 445 | ||
446 | exit: | 446 | exit: |
447 | return retval; | 447 | return retval; |
448 | } | 448 | } |
449 | 449 | ||
450 | /** | 450 | /** |
451 | * usb_alphatrack_poll | 451 | * usb_alphatrack_poll |
452 | */ | 452 | */ |
453 | static unsigned int usb_alphatrack_poll(struct file *file, poll_table * wait) | 453 | static unsigned int usb_alphatrack_poll(struct file *file, poll_table *wait) |
454 | { | 454 | { |
455 | struct usb_alphatrack *dev; | 455 | struct usb_alphatrack *dev; |
456 | unsigned int mask = 0; | 456 | unsigned int mask = 0; |
457 | 457 | ||
458 | dev = file->private_data; | 458 | dev = file->private_data; |
459 | 459 | ||
460 | poll_wait(file, &dev->read_wait, wait); | 460 | poll_wait(file, &dev->read_wait, wait); |
461 | poll_wait(file, &dev->write_wait, wait); | 461 | poll_wait(file, &dev->write_wait, wait); |
462 | 462 | ||
463 | if (dev->ring_head != dev->ring_tail) | 463 | if (dev->ring_head != dev->ring_tail) |
464 | mask |= POLLIN | POLLRDNORM; | 464 | mask |= POLLIN | POLLRDNORM; |
465 | if (!dev->interrupt_out_busy) | 465 | if (!dev->interrupt_out_busy) |
466 | mask |= POLLOUT | POLLWRNORM; | 466 | mask |= POLLOUT | POLLWRNORM; |
467 | 467 | ||
468 | return mask; | 468 | return mask; |
469 | } | 469 | } |
470 | 470 | ||
471 | /** | 471 | /** |
472 | * usb_alphatrack_read | 472 | * usb_alphatrack_read |
473 | */ | 473 | */ |
474 | static ssize_t usb_alphatrack_read(struct file *file, char __user *buffer, | 474 | static ssize_t usb_alphatrack_read(struct file *file, char __user *buffer, |
475 | size_t count, loff_t *ppos) | 475 | size_t count, loff_t *ppos) |
476 | { | 476 | { |
477 | struct usb_alphatrack *dev; | 477 | struct usb_alphatrack *dev; |
478 | int retval = 0; | 478 | int retval = 0; |
479 | 479 | ||
480 | int c = 0; | 480 | int c = 0; |
481 | 481 | ||
482 | dev = file->private_data; | 482 | dev = file->private_data; |
483 | 483 | ||
484 | /* verify that we actually have some data to read */ | 484 | /* verify that we actually have some data to read */ |
485 | if (count == 0) | 485 | if (count == 0) |
486 | goto exit; | 486 | goto exit; |
487 | 487 | ||
488 | /* lock this object */ | 488 | /* lock this object */ |
489 | if (mutex_lock_interruptible(&dev->mtx)) { | 489 | if (mutex_lock_interruptible(&dev->mtx)) { |
490 | retval = -ERESTARTSYS; | 490 | retval = -ERESTARTSYS; |
491 | goto exit; | 491 | goto exit; |
492 | } | 492 | } |
493 | 493 | ||
494 | /* verify that the device wasn't unplugged */ | 494 | /* verify that the device wasn't unplugged */ |
495 | if (dev->intf == NULL) { | 495 | if (dev->intf == NULL) { |
496 | retval = -ENODEV; | 496 | retval = -ENODEV; |
497 | err("No device or device unplugged %d\n", retval); | 497 | err("No device or device unplugged %d\n", retval); |
498 | goto unlock_exit; | 498 | goto unlock_exit; |
499 | } | 499 | } |
500 | 500 | ||
501 | while (dev->ring_head == dev->ring_tail) { | 501 | while (dev->ring_head == dev->ring_tail) { |
502 | if (file->f_flags & O_NONBLOCK) { | 502 | if (file->f_flags & O_NONBLOCK) { |
503 | retval = -EAGAIN; | 503 | retval = -EAGAIN; |
504 | goto unlock_exit; | 504 | goto unlock_exit; |
505 | } | 505 | } |
506 | dev->interrupt_in_done = 0; | 506 | dev->interrupt_in_done = 0; |
507 | retval = | 507 | retval = |
508 | wait_event_interruptible(dev->read_wait, | 508 | wait_event_interruptible(dev->read_wait, |
509 | dev->interrupt_in_done); | 509 | dev->interrupt_in_done); |
510 | if (retval < 0) | 510 | if (retval < 0) |
511 | goto unlock_exit; | 511 | goto unlock_exit; |
512 | } | 512 | } |
513 | 513 | ||
514 | alphatrack_ocmd_info(&dev->intf->dev, | 514 | alphatrack_ocmd_info(&dev->intf->dev, |
515 | &(*dev->ring_buffer)[dev->ring_tail].cmd, "%s", | 515 | &(*dev->ring_buffer)[dev->ring_tail].cmd, "%s", |
516 | ": copying to userspace"); | 516 | ": copying to userspace"); |
517 | 517 | ||
518 | c = 0; | 518 | c = 0; |
519 | while ((c < count) && (dev->ring_tail != dev->ring_head)) { | 519 | while ((c < count) && (dev->ring_tail != dev->ring_head)) { |
520 | if (copy_to_user | 520 | if (copy_to_user |
521 | (&buffer[c], &(*dev->ring_buffer)[dev->ring_tail], | 521 | (&buffer[c], &(*dev->ring_buffer)[dev->ring_tail], |
522 | INPUT_CMD_SIZE)) { | 522 | INPUT_CMD_SIZE)) { |
523 | retval = -EFAULT; | 523 | retval = -EFAULT; |
524 | goto unlock_exit; | 524 | goto unlock_exit; |
525 | } | 525 | } |
526 | dev->ring_tail = (dev->ring_tail + 1) % ring_buffer_size; | 526 | dev->ring_tail = (dev->ring_tail + 1) % ring_buffer_size; |
527 | c += INPUT_CMD_SIZE; | 527 | c += INPUT_CMD_SIZE; |
528 | dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", | 528 | dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", |
529 | __func__, dev->ring_head, dev->ring_tail); | 529 | __func__, dev->ring_head, dev->ring_tail); |
530 | } | 530 | } |
531 | retval = c; | 531 | retval = c; |
532 | 532 | ||
533 | unlock_exit: | 533 | unlock_exit: |
534 | /* unlock the device */ | 534 | /* unlock the device */ |
535 | mutex_unlock(&dev->mtx); | 535 | mutex_unlock(&dev->mtx); |
536 | 536 | ||
537 | exit: | 537 | exit: |
538 | return retval; | 538 | return retval; |
539 | } | 539 | } |
540 | 540 | ||
541 | /** | 541 | /** |
542 | * usb_alphatrack_write | 542 | * usb_alphatrack_write |
543 | */ | 543 | */ |
544 | static ssize_t usb_alphatrack_write(struct file *file, | 544 | static ssize_t usb_alphatrack_write(struct file *file, |
545 | const char __user *buffer, size_t count, | 545 | const char __user *buffer, size_t count, |
546 | loff_t *ppos) | 546 | loff_t *ppos) |
547 | { | 547 | { |
548 | struct usb_alphatrack *dev; | 548 | struct usb_alphatrack *dev; |
549 | size_t bytes_to_write; | 549 | size_t bytes_to_write; |
550 | int retval = 0; | 550 | int retval = 0; |
551 | 551 | ||
552 | dev = file->private_data; | 552 | dev = file->private_data; |
553 | 553 | ||
554 | /* verify that we actually have some data to write */ | 554 | /* verify that we actually have some data to write */ |
555 | if (count == 0) | 555 | if (count == 0) |
556 | goto exit; | 556 | goto exit; |
557 | 557 | ||
558 | /* lock this object */ | 558 | /* lock this object */ |
559 | if (mutex_lock_interruptible(&dev->mtx)) { | 559 | if (mutex_lock_interruptible(&dev->mtx)) { |
560 | retval = -ERESTARTSYS; | 560 | retval = -ERESTARTSYS; |
561 | goto exit; | 561 | goto exit; |
562 | } | 562 | } |
563 | 563 | ||
564 | /* verify that the device wasn't unplugged */ | 564 | /* verify that the device wasn't unplugged */ |
565 | if (dev->intf == NULL) { | 565 | if (dev->intf == NULL) { |
566 | retval = -ENODEV; | 566 | retval = -ENODEV; |
567 | err("No device or device unplugged %d\n", retval); | 567 | err("No device or device unplugged %d\n", retval); |
568 | goto unlock_exit; | 568 | goto unlock_exit; |
569 | } | 569 | } |
570 | 570 | ||
571 | /* wait until previous transfer is finished */ | 571 | /* wait until previous transfer is finished */ |
572 | if (dev->interrupt_out_busy) { | 572 | if (dev->interrupt_out_busy) { |
573 | if (file->f_flags & O_NONBLOCK) { | 573 | if (file->f_flags & O_NONBLOCK) { |
574 | retval = -EAGAIN; | 574 | retval = -EAGAIN; |
575 | goto unlock_exit; | 575 | goto unlock_exit; |
576 | } | 576 | } |
577 | retval = | 577 | retval = |
578 | wait_event_interruptible(dev->write_wait, | 578 | wait_event_interruptible(dev->write_wait, |
579 | !dev->interrupt_out_busy); | 579 | !dev->interrupt_out_busy); |
580 | if (retval < 0) | 580 | if (retval < 0) |
581 | goto unlock_exit; | 581 | goto unlock_exit; |
582 | } | 582 | } |
583 | 583 | ||
584 | /* write the data into interrupt_out_buffer from userspace */ | 584 | /* write the data into interrupt_out_buffer from userspace */ |
585 | /* FIXME - if you write more than 12 bytes this breaks */ | 585 | /* FIXME - if you write more than 12 bytes this breaks */ |
586 | bytes_to_write = | 586 | bytes_to_write = |
587 | min(count, write_buffer_size * dev->interrupt_out_endpoint_size); | 587 | min(count, write_buffer_size * dev->interrupt_out_endpoint_size); |
588 | if (bytes_to_write < count) | 588 | if (bytes_to_write < count) |
589 | dev_warn(&dev->intf->dev, | 589 | dev_warn(&dev->intf->dev, |
590 | "Write buffer overflow, %zd bytes dropped\n", | 590 | "Write buffer overflow, %zd bytes dropped\n", |
591 | count - bytes_to_write); | 591 | count - bytes_to_write); |
592 | 592 | ||
593 | dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", | 593 | dbg_info(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", |
594 | __func__, count, bytes_to_write); | 594 | __func__, count, bytes_to_write); |
595 | 595 | ||
596 | if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { | 596 | if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { |
597 | retval = -EFAULT; | 597 | retval = -EFAULT; |
598 | goto unlock_exit; | 598 | goto unlock_exit; |
599 | } | 599 | } |
600 | 600 | ||
601 | if (dev->interrupt_out_endpoint == NULL) { | 601 | if (dev->interrupt_out_endpoint == NULL) { |
602 | err("Endpoint should not be be null!\n"); | 602 | err("Endpoint should not be be null!\n"); |
603 | goto unlock_exit; | 603 | goto unlock_exit; |
604 | } | 604 | } |
605 | 605 | ||
606 | /* send off the urb */ | 606 | /* send off the urb */ |
607 | usb_fill_int_urb(dev->interrupt_out_urb, | 607 | usb_fill_int_urb(dev->interrupt_out_urb, |
608 | interface_to_usbdev(dev->intf), | 608 | interface_to_usbdev(dev->intf), |
609 | usb_sndintpipe(interface_to_usbdev(dev->intf), | 609 | usb_sndintpipe(interface_to_usbdev(dev->intf), |
610 | dev->interrupt_out_endpoint-> | 610 | dev->interrupt_out_endpoint-> |
611 | bEndpointAddress), | 611 | bEndpointAddress), |
612 | dev->interrupt_out_buffer, bytes_to_write, | 612 | dev->interrupt_out_buffer, bytes_to_write, |
613 | usb_alphatrack_interrupt_out_callback, dev, | 613 | usb_alphatrack_interrupt_out_callback, dev, |
614 | dev->interrupt_out_interval); | 614 | dev->interrupt_out_interval); |
615 | dev->interrupt_out_busy = 1; | 615 | dev->interrupt_out_busy = 1; |
616 | atomic_inc(&dev->writes_pending); | 616 | atomic_inc(&dev->writes_pending); |
617 | wmb(); | 617 | wmb(); |
618 | 618 | ||
619 | retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); | 619 | retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); |
620 | if (retval) { | 620 | if (retval) { |
621 | dev->interrupt_out_busy = 0; | 621 | dev->interrupt_out_busy = 0; |
622 | err("Couldn't submit interrupt_out_urb %d\n", retval); | 622 | err("Couldn't submit interrupt_out_urb %d\n", retval); |
623 | atomic_dec(&dev->writes_pending); | 623 | atomic_dec(&dev->writes_pending); |
624 | goto unlock_exit; | 624 | goto unlock_exit; |
625 | } | 625 | } |
626 | retval = bytes_to_write; | 626 | retval = bytes_to_write; |
627 | 627 | ||
628 | unlock_exit: | 628 | unlock_exit: |
629 | /* unlock the device */ | 629 | /* unlock the device */ |
630 | mutex_unlock(&dev->mtx); | 630 | mutex_unlock(&dev->mtx); |
631 | 631 | ||
632 | exit: | 632 | exit: |
633 | return retval; | 633 | return retval; |
634 | } | 634 | } |
635 | 635 | ||
636 | /* file operations needed when we register this driver */ | 636 | /* file operations needed when we register this driver */ |
637 | static const struct file_operations usb_alphatrack_fops = { | 637 | static const struct file_operations usb_alphatrack_fops = { |
638 | .owner = THIS_MODULE, | 638 | .owner = THIS_MODULE, |
639 | .read = usb_alphatrack_read, | 639 | .read = usb_alphatrack_read, |
640 | .write = usb_alphatrack_write, | 640 | .write = usb_alphatrack_write, |
641 | .open = usb_alphatrack_open, | 641 | .open = usb_alphatrack_open, |
642 | .release = usb_alphatrack_release, | 642 | .release = usb_alphatrack_release, |
643 | .poll = usb_alphatrack_poll, | 643 | .poll = usb_alphatrack_poll, |
644 | .llseek = no_llseek, | 644 | .llseek = no_llseek, |
645 | }; | 645 | }; |
646 | 646 | ||
647 | /* | 647 | /* |
648 | * usb class driver info in order to get a minor number from the usb core, | 648 | * usb class driver info in order to get a minor number from the usb core, |
649 | * and to have the device registered with the driver core | 649 | * and to have the device registered with the driver core |
650 | */ | 650 | */ |
651 | 651 | ||
652 | static struct usb_class_driver usb_alphatrack_class = { | 652 | static struct usb_class_driver usb_alphatrack_class = { |
653 | .name = "alphatrack%d", | 653 | .name = "alphatrack%d", |
654 | .fops = &usb_alphatrack_fops, | 654 | .fops = &usb_alphatrack_fops, |
655 | .minor_base = USB_ALPHATRACK_MINOR_BASE, | 655 | .minor_base = USB_ALPHATRACK_MINOR_BASE, |
656 | }; | 656 | }; |
657 | 657 | ||
658 | /** | 658 | /** |
659 | * usb_alphatrack_probe | 659 | * usb_alphatrack_probe |
660 | * | 660 | * |
661 | * Called by the usb core when a new device is connected that it thinks | 661 | * Called by the usb core when a new device is connected that it thinks |
662 | * this driver might be interested in. | 662 | * this driver might be interested in. |
663 | */ | 663 | */ |
664 | static int usb_alphatrack_probe(struct usb_interface *intf, | 664 | static int usb_alphatrack_probe(struct usb_interface *intf, |
665 | const struct usb_device_id *id) | 665 | const struct usb_device_id *id) |
666 | { | 666 | { |
667 | struct usb_device *udev = interface_to_usbdev(intf); | 667 | struct usb_device *udev = interface_to_usbdev(intf); |
668 | struct usb_alphatrack *dev = NULL; | 668 | struct usb_alphatrack *dev = NULL; |
669 | struct usb_host_interface *iface_desc; | 669 | struct usb_host_interface *iface_desc; |
670 | struct usb_endpoint_descriptor *endpoint; | 670 | struct usb_endpoint_descriptor *endpoint; |
671 | int i; | 671 | int i; |
672 | int true_size; | 672 | int true_size; |
673 | int retval = -ENOMEM; | 673 | int retval = -ENOMEM; |
674 | 674 | ||
675 | /* allocate memory for our device state and initialize it */ | 675 | /* allocate memory for our device state and initialize it */ |
676 | 676 | ||
677 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 677 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
678 | if (dev == NULL) { | 678 | if (dev == NULL) { |
679 | dev_err(&intf->dev, "Out of memory\n"); | 679 | dev_err(&intf->dev, "Out of memory\n"); |
680 | goto exit; | 680 | goto exit; |
681 | } | 681 | } |
682 | mutex_init(&dev->mtx); | 682 | mutex_init(&dev->mtx); |
683 | dev->intf = intf; | 683 | dev->intf = intf; |
684 | init_waitqueue_head(&dev->read_wait); | 684 | init_waitqueue_head(&dev->read_wait); |
685 | init_waitqueue_head(&dev->write_wait); | 685 | init_waitqueue_head(&dev->write_wait); |
686 | 686 | ||
687 | iface_desc = intf->cur_altsetting; | 687 | iface_desc = intf->cur_altsetting; |
688 | 688 | ||
689 | /* set up the endpoint information */ | 689 | /* set up the endpoint information */ |
690 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | 690 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { |
691 | endpoint = &iface_desc->endpoint[i].desc; | 691 | endpoint = &iface_desc->endpoint[i].desc; |
692 | 692 | ||
693 | if (usb_endpoint_is_int_in(endpoint)) | 693 | if (usb_endpoint_is_int_in(endpoint)) |
694 | dev->interrupt_in_endpoint = endpoint; | 694 | dev->interrupt_in_endpoint = endpoint; |
695 | 695 | ||
696 | if (usb_endpoint_is_int_out(endpoint)) | 696 | if (usb_endpoint_is_int_out(endpoint)) |
697 | dev->interrupt_out_endpoint = endpoint; | 697 | dev->interrupt_out_endpoint = endpoint; |
698 | } | 698 | } |
699 | if (dev->interrupt_in_endpoint == NULL) { | 699 | if (dev->interrupt_in_endpoint == NULL) { |
700 | dev_err(&intf->dev, "Interrupt in endpoint not found\n"); | 700 | dev_err(&intf->dev, "Interrupt in endpoint not found\n"); |
701 | goto error; | 701 | goto error; |
702 | } | 702 | } |
703 | if (dev->interrupt_out_endpoint == NULL) | 703 | if (dev->interrupt_out_endpoint == NULL) |
704 | dev_warn(&intf->dev, | 704 | dev_warn(&intf->dev, |
705 | "Interrupt out endpoint not found" | 705 | "Interrupt out endpoint not found" |
706 | "(using control endpoint instead)\n"); | 706 | "(using control endpoint instead)\n"); |
707 | 707 | ||
708 | dev->interrupt_in_endpoint_size = | 708 | dev->interrupt_in_endpoint_size = |
709 | le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); | 709 | le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); |
710 | 710 | ||
711 | if (dev->interrupt_in_endpoint_size != 64) | 711 | if (dev->interrupt_in_endpoint_size != 64) |
712 | dev_warn(&intf->dev, "Interrupt in endpoint size is not 64!\n"); | 712 | dev_warn(&intf->dev, "Interrupt in endpoint size is not 64!\n"); |
713 | 713 | ||
714 | if (ring_buffer_size == 0) | 714 | if (ring_buffer_size == 0) |
715 | ring_buffer_size = RING_BUFFER_SIZE; | 715 | ring_buffer_size = RING_BUFFER_SIZE; |
716 | 716 | ||
717 | true_size = min(ring_buffer_size, RING_BUFFER_SIZE); | 717 | true_size = min(ring_buffer_size, RING_BUFFER_SIZE); |
718 | 718 | ||
719 | /* FIXME - there are more usb_alloc routines for dma correctness. | 719 | /* FIXME - there are more usb_alloc routines for dma correctness. |
720 | Needed? */ | 720 | Needed? */ |
721 | dev->ring_buffer = | 721 | dev->ring_buffer = |
722 | kmalloc((true_size * sizeof(struct alphatrack_icmd)), GFP_KERNEL); | 722 | kmalloc((true_size * sizeof(struct alphatrack_icmd)), GFP_KERNEL); |
723 | 723 | ||
724 | if (!dev->ring_buffer) { | 724 | if (!dev->ring_buffer) { |
725 | dev_err(&intf->dev, | 725 | dev_err(&intf->dev, |
726 | "Couldn't allocate input ring_buffer of size %d\n", | 726 | "Couldn't allocate input ring_buffer of size %d\n", |
727 | true_size); | 727 | true_size); |
728 | goto error; | 728 | goto error; |
729 | } | 729 | } |
730 | 730 | ||
731 | dev->interrupt_in_buffer = | 731 | dev->interrupt_in_buffer = |
732 | kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); | 732 | kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); |
733 | 733 | ||
734 | if (!dev->interrupt_in_buffer) { | 734 | if (!dev->interrupt_in_buffer) { |
735 | dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n"); | 735 | dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n"); |
736 | goto error; | 736 | goto error; |
737 | } | 737 | } |
738 | dev->oldi_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); | 738 | dev->oldi_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); |
739 | if (!dev->oldi_buffer) { | 739 | if (!dev->oldi_buffer) { |
740 | dev_err(&intf->dev, "Couldn't allocate old buffer\n"); | 740 | dev_err(&intf->dev, "Couldn't allocate old buffer\n"); |
741 | goto error; | 741 | goto error; |
742 | } | 742 | } |
743 | dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); | 743 | dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); |
744 | if (!dev->interrupt_in_urb) { | 744 | if (!dev->interrupt_in_urb) { |
745 | dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); | 745 | dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); |
746 | goto error; | 746 | goto error; |
747 | } | 747 | } |
748 | 748 | ||
749 | dev->interrupt_out_endpoint_size = | 749 | dev->interrupt_out_endpoint_size = |
750 | dev->interrupt_out_endpoint ? le16_to_cpu(dev-> | 750 | dev->interrupt_out_endpoint ? le16_to_cpu(dev-> |
751 | interrupt_out_endpoint-> | 751 | interrupt_out_endpoint-> |
752 | wMaxPacketSize) : udev-> | 752 | wMaxPacketSize) : udev-> |
753 | descriptor.bMaxPacketSize0; | 753 | descriptor.bMaxPacketSize0; |
754 | 754 | ||
755 | if (dev->interrupt_out_endpoint_size != 64) | 755 | if (dev->interrupt_out_endpoint_size != 64) |
756 | dev_warn(&intf->dev, | 756 | dev_warn(&intf->dev, |
757 | "Interrupt out endpoint size is not 64!)\n"); | 757 | "Interrupt out endpoint size is not 64!)\n"); |
758 | 758 | ||
759 | if (write_buffer_size == 0) | 759 | if (write_buffer_size == 0) |
760 | write_buffer_size = WRITE_BUFFER_SIZE; | 760 | write_buffer_size = WRITE_BUFFER_SIZE; |
761 | true_size = min(write_buffer_size, WRITE_BUFFER_SIZE); | 761 | true_size = min(write_buffer_size, WRITE_BUFFER_SIZE); |
762 | 762 | ||
763 | dev->interrupt_out_buffer = | 763 | dev->interrupt_out_buffer = |
764 | kmalloc(true_size * dev->interrupt_out_endpoint_size, GFP_KERNEL); | 764 | kmalloc(true_size * dev->interrupt_out_endpoint_size, GFP_KERNEL); |
765 | 765 | ||
766 | if (!dev->interrupt_out_buffer) { | 766 | if (!dev->interrupt_out_buffer) { |
767 | dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n"); | 767 | dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n"); |
768 | goto error; | 768 | goto error; |
769 | } | 769 | } |
770 | 770 | ||
771 | dev->write_buffer = | 771 | dev->write_buffer = |
772 | kmalloc(true_size * sizeof(struct alphatrack_ocmd), GFP_KERNEL); | 772 | kmalloc(true_size * sizeof(struct alphatrack_ocmd), GFP_KERNEL); |
773 | 773 | ||
774 | if (!dev->write_buffer) { | 774 | if (!dev->write_buffer) { |
775 | dev_err(&intf->dev, "Couldn't allocate write_buffer\n"); | 775 | dev_err(&intf->dev, "Couldn't allocate write_buffer\n"); |
776 | goto error; | 776 | goto error; |
777 | } | 777 | } |
778 | 778 | ||
779 | dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); | 779 | dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); |
780 | if (!dev->interrupt_out_urb) { | 780 | if (!dev->interrupt_out_urb) { |
781 | dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); | 781 | dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); |
782 | goto error; | 782 | goto error; |
783 | } | 783 | } |
784 | dev->interrupt_in_interval = | 784 | dev->interrupt_in_interval = |
785 | min_interrupt_in_interval > | 785 | min_interrupt_in_interval > |
786 | dev->interrupt_in_endpoint-> | 786 | dev->interrupt_in_endpoint-> |
787 | bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint-> | 787 | bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint-> |
788 | bInterval; | 788 | bInterval; |
789 | if (dev->interrupt_out_endpoint) | 789 | if (dev->interrupt_out_endpoint) |
790 | dev->interrupt_out_interval = | 790 | dev->interrupt_out_interval = |
791 | min_interrupt_out_interval > | 791 | min_interrupt_out_interval > |
792 | dev->interrupt_out_endpoint-> | 792 | dev->interrupt_out_endpoint-> |
793 | bInterval ? min_interrupt_out_interval : dev-> | 793 | bInterval ? min_interrupt_out_interval : dev-> |
794 | interrupt_out_endpoint->bInterval; | 794 | interrupt_out_endpoint->bInterval; |
795 | 795 | ||
796 | /* we can register the device now, as it is ready */ | 796 | /* we can register the device now, as it is ready */ |
797 | usb_set_intfdata(intf, dev); | 797 | usb_set_intfdata(intf, dev); |
798 | 798 | ||
799 | atomic_set(&dev->writes_pending, 0); | 799 | atomic_set(&dev->writes_pending, 0); |
800 | retval = usb_register_dev(intf, &usb_alphatrack_class); | 800 | retval = usb_register_dev(intf, &usb_alphatrack_class); |
801 | if (retval) { | 801 | if (retval) { |
802 | /* something prevented us from registering this driver */ | 802 | /* something prevented us from registering this driver */ |
803 | dev_err(&intf->dev, | 803 | dev_err(&intf->dev, |
804 | "Not able to get a minor for this device.\n"); | 804 | "Not able to get a minor for this device.\n"); |
805 | usb_set_intfdata(intf, NULL); | 805 | usb_set_intfdata(intf, NULL); |
806 | goto error; | 806 | goto error; |
807 | } | 807 | } |
808 | 808 | ||
809 | /* let the user know what node this device is now attached to */ | 809 | /* let the user know what node this device is now attached to */ |
810 | dev_info(&intf->dev, | 810 | dev_info(&intf->dev, |
811 | "Alphatrack Device #%d now attached to major %d minor %d\n", | 811 | "Alphatrack Device #%d now attached to major %d minor %d\n", |
812 | (intf->minor - USB_ALPHATRACK_MINOR_BASE), USB_MAJOR, | 812 | (intf->minor - USB_ALPHATRACK_MINOR_BASE), USB_MAJOR, |
813 | intf->minor); | 813 | intf->minor); |
814 | 814 | ||
815 | exit: | 815 | exit: |
816 | return retval; | 816 | return retval; |
817 | 817 | ||
818 | error: | 818 | error: |
819 | usb_alphatrack_delete(dev); | 819 | usb_alphatrack_delete(dev); |
820 | 820 | ||
821 | return retval; | 821 | return retval; |
822 | } | 822 | } |
823 | 823 | ||
824 | /** | 824 | /** |
825 | * usb_alphatrack_disconnect | 825 | * usb_alphatrack_disconnect |
826 | * | 826 | * |
827 | * Called by the usb core when the device is removed from the system. | 827 | * Called by the usb core when the device is removed from the system. |
828 | */ | 828 | */ |
829 | static void usb_alphatrack_disconnect(struct usb_interface *intf) | 829 | static void usb_alphatrack_disconnect(struct usb_interface *intf) |
830 | { | 830 | { |
831 | struct usb_alphatrack *dev; | 831 | struct usb_alphatrack *dev; |
832 | int minor; | 832 | int minor; |
833 | 833 | ||
834 | mutex_lock(&disconnect_mutex); | 834 | mutex_lock(&disconnect_mutex); |
835 | 835 | ||
836 | dev = usb_get_intfdata(intf); | 836 | dev = usb_get_intfdata(intf); |
837 | usb_set_intfdata(intf, NULL); | 837 | usb_set_intfdata(intf, NULL); |
838 | 838 | ||
839 | mutex_lock(&dev->mtx); | 839 | mutex_lock(&dev->mtx); |
840 | 840 | ||
841 | minor = intf->minor; | 841 | minor = intf->minor; |
842 | 842 | ||
843 | /* give back our minor */ | 843 | /* give back our minor */ |
844 | usb_deregister_dev(intf, &usb_alphatrack_class); | 844 | usb_deregister_dev(intf, &usb_alphatrack_class); |
845 | 845 | ||
846 | /* if the device is not opened, then we clean up right now */ | 846 | /* if the device is not opened, then we clean up right now */ |
847 | if (!dev->open_count) { | 847 | if (!dev->open_count) { |
848 | mutex_unlock(&dev->mtx); | 848 | mutex_unlock(&dev->mtx); |
849 | usb_alphatrack_delete(dev); | 849 | usb_alphatrack_delete(dev); |
850 | } else { | 850 | } else { |
851 | dev->intf = NULL; | 851 | dev->intf = NULL; |
852 | mutex_unlock(&dev->mtx); | 852 | mutex_unlock(&dev->mtx); |
853 | } | 853 | } |
854 | 854 | ||
855 | atomic_set(&dev->writes_pending, 0); | 855 | atomic_set(&dev->writes_pending, 0); |
856 | mutex_unlock(&disconnect_mutex); | 856 | mutex_unlock(&disconnect_mutex); |
857 | 857 | ||
858 | dev_info(&intf->dev, "Alphatrack Surface #%d now disconnected\n", | 858 | dev_info(&intf->dev, "Alphatrack Surface #%d now disconnected\n", |
859 | (minor - USB_ALPHATRACK_MINOR_BASE)); | 859 | (minor - USB_ALPHATRACK_MINOR_BASE)); |
860 | } | 860 | } |
861 | 861 | ||
862 | /* usb specific object needed to register this driver with the usb subsystem */ | 862 | /* usb specific object needed to register this driver with the usb subsystem */ |
863 | static struct usb_driver usb_alphatrack_driver = { | 863 | static struct usb_driver usb_alphatrack_driver = { |
864 | .name = "alphatrack", | 864 | .name = "alphatrack", |
865 | .probe = usb_alphatrack_probe, | 865 | .probe = usb_alphatrack_probe, |
866 | .disconnect = usb_alphatrack_disconnect, | 866 | .disconnect = usb_alphatrack_disconnect, |
867 | .id_table = usb_alphatrack_table, | 867 | .id_table = usb_alphatrack_table, |
868 | }; | 868 | }; |
869 | 869 | ||
870 | module_usb_driver(usb_alphatrack_driver); | 870 | module_usb_driver(usb_alphatrack_driver); |
871 | 871 |
drivers/staging/frontier/tranzport.c
1 | /* | 1 | /* |
2 | * Frontier Designs Tranzport driver | 2 | * Frontier Designs Tranzport driver |
3 | * | 3 | * |
4 | * Copyright (C) 2007 Michael Taht (m@taht.net) | 4 | * Copyright (C) 2007 Michael Taht (m@taht.net) |
5 | * | 5 | * |
6 | * Based on the usbled driver and ldusb drivers by | 6 | * Based on the usbled driver and ldusb drivers by |
7 | * | 7 | * |
8 | * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com) | 8 | * Copyright (C) 2004 Greg Kroah-Hartman (greg@kroah.com) |
9 | * Copyright (C) 2005 Michael Hund <mhund@ld-didactic.de> | 9 | * Copyright (C) 2005 Michael Hund <mhund@ld-didactic.de> |
10 | * | 10 | * |
11 | * The ldusb driver was, in turn, derived from Lego USB Tower driver | 11 | * The ldusb driver was, in turn, derived from Lego USB Tower driver |
12 | * Copyright (C) 2003 David Glance <advidgsf@sourceforge.net> | 12 | * Copyright (C) 2003 David Glance <advidgsf@sourceforge.net> |
13 | * 2001-2004 Juergen Stuber <starblue@users.sourceforge.net> | 13 | * 2001-2004 Juergen Stuber <starblue@users.sourceforge.net> |
14 | * | 14 | * |
15 | * This program is free software; you can redistribute it and/or | 15 | * This program is free software; you can redistribute it and/or |
16 | * modify it under the terms of the GNU General Public License as | 16 | * modify it under the terms of the GNU General Public License as |
17 | * published by the Free Software Foundation, version 2. | 17 | * published by the Free Software Foundation, version 2. |
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * This driver uses a ring buffer for time critical reading of | 22 | * This driver uses a ring buffer for time critical reading of |
23 | * interrupt in reports and provides read and write methods for | 23 | * interrupt in reports and provides read and write methods for |
24 | * raw interrupt reports. | 24 | * raw interrupt reports. |
25 | */ | 25 | */ |
26 | 26 | ||
27 | /* Note: this currently uses a dumb ringbuffer for reads and writes. | 27 | /* Note: this currently uses a dumb ringbuffer for reads and writes. |
28 | * A more optimal driver would cache and kill off outstanding urbs that are | 28 | * A more optimal driver would cache and kill off outstanding urbs that are |
29 | * now invalid, and ignore ones that already were in the queue but valid | 29 | * now invalid, and ignore ones that already were in the queue but valid |
30 | * as we only have 17 commands for the tranzport. In particular this is | 30 | * as we only have 17 commands for the tranzport. In particular this is |
31 | * key for getting lights to flash in time as otherwise many commands | 31 | * key for getting lights to flash in time as otherwise many commands |
32 | * can be buffered up before the light change makes it to the interface. | 32 | * can be buffered up before the light change makes it to the interface. |
33 | */ | 33 | */ |
34 | 34 | ||
35 | #include <linux/kernel.h> | 35 | #include <linux/kernel.h> |
36 | #include <linux/errno.h> | 36 | #include <linux/errno.h> |
37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/module.h> | 39 | #include <linux/module.h> |
40 | #include <linux/mutex.h> | 40 | #include <linux/mutex.h> |
41 | 41 | ||
42 | #include <linux/uaccess.h> | 42 | #include <linux/uaccess.h> |
43 | #include <linux/input.h> | 43 | #include <linux/input.h> |
44 | #include <linux/usb.h> | 44 | #include <linux/usb.h> |
45 | #include <linux/poll.h> | 45 | #include <linux/poll.h> |
46 | 46 | ||
47 | /* Define these values to match your devices */ | 47 | /* Define these values to match your devices */ |
48 | #define VENDOR_ID 0x165b | 48 | #define VENDOR_ID 0x165b |
49 | #define PRODUCT_ID 0x8101 | 49 | #define PRODUCT_ID 0x8101 |
50 | 50 | ||
51 | #ifdef CONFIG_USB_DYNAMIC_MINORS | 51 | #ifdef CONFIG_USB_DYNAMIC_MINORS |
52 | #define USB_TRANZPORT_MINOR_BASE 0 | 52 | #define USB_TRANZPORT_MINOR_BASE 0 |
53 | #else /* FIXME 177- is the another driver's minor - apply for a minor soon */ | 53 | #else /* FIXME 177- is the another driver's minor - apply for a minor soon */ |
54 | #define USB_TRANZPORT_MINOR_BASE 177 | 54 | #define USB_TRANZPORT_MINOR_BASE 177 |
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | /* table of devices that work with this driver */ | 57 | /* table of devices that work with this driver */ |
58 | static const struct usb_device_id usb_tranzport_table[] = { | 58 | static const struct usb_device_id usb_tranzport_table[] = { |
59 | {USB_DEVICE(VENDOR_ID, PRODUCT_ID)}, | 59 | {USB_DEVICE(VENDOR_ID, PRODUCT_ID)}, |
60 | {} /* Terminating entry */ | 60 | {} /* Terminating entry */ |
61 | }; | 61 | }; |
62 | 62 | ||
63 | MODULE_DEVICE_TABLE(usb, usb_tranzport_table); | 63 | MODULE_DEVICE_TABLE(usb, usb_tranzport_table); |
64 | MODULE_VERSION("0.35"); | 64 | MODULE_VERSION("0.35"); |
65 | MODULE_AUTHOR("Mike Taht <m@taht.net>"); | 65 | MODULE_AUTHOR("Mike Taht <m@taht.net>"); |
66 | MODULE_DESCRIPTION("Tranzport USB Driver"); | 66 | MODULE_DESCRIPTION("Tranzport USB Driver"); |
67 | MODULE_LICENSE("GPL"); | 67 | MODULE_LICENSE("GPL"); |
68 | MODULE_SUPPORTED_DEVICE("Frontier Designs Tranzport Control Surface"); | 68 | MODULE_SUPPORTED_DEVICE("Frontier Designs Tranzport Control Surface"); |
69 | 69 | ||
70 | #define SUPPRESS_EXTRA_OFFLINE_EVENTS 1 | 70 | #define SUPPRESS_EXTRA_OFFLINE_EVENTS 1 |
71 | #define COMPRESS_WHEEL_EVENTS 1 | 71 | #define COMPRESS_WHEEL_EVENTS 1 |
72 | #define BUFFERED_READS 1 | 72 | #define BUFFERED_READS 1 |
73 | #define RING_BUFFER_SIZE 1000 | 73 | #define RING_BUFFER_SIZE 1000 |
74 | #define WRITE_BUFFER_SIZE 34 | 74 | #define WRITE_BUFFER_SIZE 34 |
75 | #define TRANZPORT_USB_TIMEOUT 10 | 75 | #define TRANZPORT_USB_TIMEOUT 10 |
76 | #define TRANZPORT_DEBUG 0 | 76 | #define TRANZPORT_DEBUG 0 |
77 | 77 | ||
78 | static int debug = TRANZPORT_DEBUG; | 78 | static int debug = TRANZPORT_DEBUG; |
79 | 79 | ||
80 | /* Use our own dbg macro */ | 80 | /* Use our own dbg macro */ |
81 | #define dbg_info(dev, format, arg...) do \ | 81 | #define dbg_info(dev, format, arg...) do \ |
82 | { if (debug) dev_info(dev , format , ## arg); } while (0) | 82 | { if (debug) dev_info(dev , format , ## arg); } while (0) |
83 | 83 | ||
84 | /* Module parameters */ | 84 | /* Module parameters */ |
85 | 85 | ||
86 | module_param(debug, int, S_IRUGO | S_IWUSR); | 86 | module_param(debug, int, S_IRUGO | S_IWUSR); |
87 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | 87 | MODULE_PARM_DESC(debug, "Debug enabled or not"); |
88 | 88 | ||
89 | /* All interrupt in transfers are collected in a ring buffer to | 89 | /* All interrupt in transfers are collected in a ring buffer to |
90 | * avoid racing conditions and get better performance of the driver. | 90 | * avoid racing conditions and get better performance of the driver. |
91 | */ | 91 | */ |
92 | 92 | ||
93 | static int ring_buffer_size = RING_BUFFER_SIZE; | 93 | static int ring_buffer_size = RING_BUFFER_SIZE; |
94 | 94 | ||
95 | module_param(ring_buffer_size, int, S_IRUGO); | 95 | module_param(ring_buffer_size, int, S_IRUGO); |
96 | MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size in reports"); | 96 | MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size in reports"); |
97 | 97 | ||
98 | /* The write_buffer can one day contain more than one interrupt out transfer. | 98 | /* The write_buffer can one day contain more than one interrupt out transfer. |
99 | */ | 99 | */ |
100 | static int write_buffer_size = WRITE_BUFFER_SIZE; | 100 | static int write_buffer_size = WRITE_BUFFER_SIZE; |
101 | module_param(write_buffer_size, int, S_IRUGO); | 101 | module_param(write_buffer_size, int, S_IRUGO); |
102 | MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); | 102 | MODULE_PARM_DESC(write_buffer_size, "Write buffer size"); |
103 | 103 | ||
104 | /* | 104 | /* |
105 | * Increase the interval for debugging purposes. | 105 | * Increase the interval for debugging purposes. |
106 | * or set to 1 to use the standard interval from the endpoint descriptors. | 106 | * or set to 1 to use the standard interval from the endpoint descriptors. |
107 | */ | 107 | */ |
108 | 108 | ||
109 | static int min_interrupt_in_interval = TRANZPORT_USB_TIMEOUT; | 109 | static int min_interrupt_in_interval = TRANZPORT_USB_TIMEOUT; |
110 | module_param(min_interrupt_in_interval, int, 0); | 110 | module_param(min_interrupt_in_interval, int, 0); |
111 | MODULE_PARM_DESC(min_interrupt_in_interval, | 111 | MODULE_PARM_DESC(min_interrupt_in_interval, |
112 | "Minimum interrupt in interval in ms"); | 112 | "Minimum interrupt in interval in ms"); |
113 | 113 | ||
114 | static int min_interrupt_out_interval = TRANZPORT_USB_TIMEOUT; | 114 | static int min_interrupt_out_interval = TRANZPORT_USB_TIMEOUT; |
115 | module_param(min_interrupt_out_interval, int, 0); | 115 | module_param(min_interrupt_out_interval, int, 0); |
116 | MODULE_PARM_DESC(min_interrupt_out_interval, | 116 | MODULE_PARM_DESC(min_interrupt_out_interval, |
117 | "Minimum interrupt out interval in ms"); | 117 | "Minimum interrupt out interval in ms"); |
118 | 118 | ||
119 | struct tranzport_cmd { | 119 | struct tranzport_cmd { |
120 | unsigned char cmd[8]; | 120 | unsigned char cmd[8]; |
121 | }; | 121 | }; |
122 | 122 | ||
123 | /* Structure to hold all of our device specific stuff */ | 123 | /* Structure to hold all of our device specific stuff */ |
124 | 124 | ||
125 | struct usb_tranzport { | 125 | struct usb_tranzport { |
126 | struct mutex mtx; /* locks this structure */ | 126 | struct mutex mtx; /* locks this structure */ |
127 | struct usb_interface *intf; /* save off the usb interface pointer */ | 127 | struct usb_interface *intf; /* save off the usb interface pointer */ |
128 | int open_count; /* number of times this port opened */ | 128 | int open_count; /* number of times this port opened */ |
129 | struct tranzport_cmd (*ring_buffer)[RING_BUFFER_SIZE]; | 129 | struct tranzport_cmd (*ring_buffer)[RING_BUFFER_SIZE]; |
130 | unsigned int ring_head; | 130 | unsigned int ring_head; |
131 | unsigned int ring_tail; | 131 | unsigned int ring_tail; |
132 | wait_queue_head_t read_wait; | 132 | wait_queue_head_t read_wait; |
133 | wait_queue_head_t write_wait; | 133 | wait_queue_head_t write_wait; |
134 | unsigned char *interrupt_in_buffer; | 134 | unsigned char *interrupt_in_buffer; |
135 | struct usb_endpoint_descriptor *interrupt_in_endpoint; | 135 | struct usb_endpoint_descriptor *interrupt_in_endpoint; |
136 | struct urb *interrupt_in_urb; | 136 | struct urb *interrupt_in_urb; |
137 | int interrupt_in_interval; | 137 | int interrupt_in_interval; |
138 | size_t interrupt_in_endpoint_size; | 138 | size_t interrupt_in_endpoint_size; |
139 | int interrupt_in_running; | 139 | int interrupt_in_running; |
140 | int interrupt_in_done; | 140 | int interrupt_in_done; |
141 | char *interrupt_out_buffer; | 141 | char *interrupt_out_buffer; |
142 | struct usb_endpoint_descriptor *interrupt_out_endpoint; | 142 | struct usb_endpoint_descriptor *interrupt_out_endpoint; |
143 | struct urb *interrupt_out_urb; | 143 | struct urb *interrupt_out_urb; |
144 | int interrupt_out_interval; | 144 | int interrupt_out_interval; |
145 | size_t interrupt_out_endpoint_size; | 145 | size_t interrupt_out_endpoint_size; |
146 | int interrupt_out_busy; | 146 | int interrupt_out_busy; |
147 | 147 | ||
148 | /* Sysfs support */ | 148 | /* Sysfs support */ |
149 | 149 | ||
150 | unsigned char enable; /* 0 if disabled 1 if enabled */ | 150 | unsigned char enable; /* 0 if disabled 1 if enabled */ |
151 | unsigned char offline; /* if the device is out of range or asleep */ | 151 | unsigned char offline; /* if the device is out of range or asleep */ |
152 | unsigned char compress_wheel; /* flag to compress wheel events */ | 152 | unsigned char compress_wheel; /* flag to compress wheel events */ |
153 | }; | 153 | }; |
154 | 154 | ||
155 | /* prevent races between open() and disconnect() */ | 155 | /* prevent races between open() and disconnect() */ |
156 | static DEFINE_MUTEX(disconnect_mutex); | 156 | static DEFINE_MUTEX(disconnect_mutex); |
157 | 157 | ||
158 | static struct usb_driver usb_tranzport_driver; | 158 | static struct usb_driver usb_tranzport_driver; |
159 | 159 | ||
160 | /** | 160 | /** |
161 | * usb_tranzport_abort_transfers | 161 | * usb_tranzport_abort_transfers |
162 | * aborts transfers and frees associated data structures | 162 | * aborts transfers and frees associated data structures |
163 | */ | 163 | */ |
164 | static void usb_tranzport_abort_transfers(struct usb_tranzport *dev) | 164 | static void usb_tranzport_abort_transfers(struct usb_tranzport *dev) |
165 | { | 165 | { |
166 | /* shutdown transfer */ | 166 | /* shutdown transfer */ |
167 | if (dev->interrupt_in_running) { | 167 | if (dev->interrupt_in_running) { |
168 | dev->interrupt_in_running = 0; | 168 | dev->interrupt_in_running = 0; |
169 | if (dev->intf) | 169 | if (dev->intf) |
170 | usb_kill_urb(dev->interrupt_in_urb); | 170 | usb_kill_urb(dev->interrupt_in_urb); |
171 | } | 171 | } |
172 | if (dev->interrupt_out_busy) | 172 | if (dev->interrupt_out_busy) |
173 | if (dev->intf) | 173 | if (dev->intf) |
174 | usb_kill_urb(dev->interrupt_out_urb); | 174 | usb_kill_urb(dev->interrupt_out_urb); |
175 | } | 175 | } |
176 | 176 | ||
177 | #define show_int(value) \ | 177 | #define show_int(value) \ |
178 | static ssize_t show_##value(struct device *dev, \ | 178 | static ssize_t show_##value(struct device *dev, \ |
179 | struct device_attribute *attr, char *buf) \ | 179 | struct device_attribute *attr, char *buf) \ |
180 | { \ | 180 | { \ |
181 | struct usb_interface *intf = to_usb_interface(dev); \ | 181 | struct usb_interface *intf = to_usb_interface(dev); \ |
182 | struct usb_tranzport *t = usb_get_intfdata(intf); \ | 182 | struct usb_tranzport *t = usb_get_intfdata(intf); \ |
183 | return sprintf(buf, "%d\n", t->value); \ | 183 | return sprintf(buf, "%d\n", t->value); \ |
184 | } \ | 184 | } \ |
185 | static DEVICE_ATTR(value, S_IRUGO, show_##value, NULL); | 185 | static DEVICE_ATTR(value, S_IRUGO, show_##value, NULL); |
186 | 186 | ||
187 | #define show_set_int(value) \ | 187 | #define show_set_int(value) \ |
188 | static ssize_t show_##value(struct device *dev, \ | 188 | static ssize_t show_##value(struct device *dev, \ |
189 | struct device_attribute *attr, char *buf) \ | 189 | struct device_attribute *attr, char *buf) \ |
190 | { \ | 190 | { \ |
191 | struct usb_interface *intf = to_usb_interface(dev); \ | 191 | struct usb_interface *intf = to_usb_interface(dev); \ |
192 | struct usb_tranzport *t = usb_get_intfdata(intf); \ | 192 | struct usb_tranzport *t = usb_get_intfdata(intf); \ |
193 | return sprintf(buf, "%d\n", t->value); \ | 193 | return sprintf(buf, "%d\n", t->value); \ |
194 | } \ | 194 | } \ |
195 | static ssize_t set_##value(struct device *dev, \ | 195 | static ssize_t set_##value(struct device *dev, \ |
196 | struct device_attribute *attr, \ | 196 | struct device_attribute *attr, \ |
197 | const char *buf, size_t count) \ | 197 | const char *buf, size_t count) \ |
198 | { \ | 198 | { \ |
199 | struct usb_interface *intf = to_usb_interface(dev); \ | 199 | struct usb_interface *intf = to_usb_interface(dev); \ |
200 | struct usb_tranzport *t = usb_get_intfdata(intf); \ | 200 | struct usb_tranzport *t = usb_get_intfdata(intf); \ |
201 | unsigned long temp; \ | 201 | unsigned long temp; \ |
202 | if (kstrtoul(buf, 10, &temp)) \ | 202 | if (kstrtoul(buf, 10, &temp)) \ |
203 | return -EINVAL; \ | 203 | return -EINVAL; \ |
204 | t->value = temp; \ | 204 | t->value = temp; \ |
205 | return count; \ | 205 | return count; \ |
206 | } \ | 206 | } \ |
207 | static DEVICE_ATTR(value, S_IWUSR | S_IRUGO, show_##value, set_##value); | 207 | static DEVICE_ATTR(value, S_IWUSR | S_IRUGO, show_##value, set_##value); |
208 | 208 | ||
209 | show_int(enable); | 209 | show_int(enable); |
210 | show_int(offline); | 210 | show_int(offline); |
211 | show_set_int(compress_wheel); | 211 | show_set_int(compress_wheel); |
212 | 212 | ||
213 | /** | 213 | /** |
214 | * usb_tranzport_delete | 214 | * usb_tranzport_delete |
215 | */ | 215 | */ |
216 | static void usb_tranzport_delete(struct usb_tranzport *dev) | 216 | static void usb_tranzport_delete(struct usb_tranzport *dev) |
217 | { | 217 | { |
218 | usb_tranzport_abort_transfers(dev); | 218 | usb_tranzport_abort_transfers(dev); |
219 | if (dev->intf != NULL) { | 219 | if (dev->intf != NULL) { |
220 | device_remove_file(&dev->intf->dev, &dev_attr_enable); | 220 | device_remove_file(&dev->intf->dev, &dev_attr_enable); |
221 | device_remove_file(&dev->intf->dev, &dev_attr_offline); | 221 | device_remove_file(&dev->intf->dev, &dev_attr_offline); |
222 | device_remove_file(&dev->intf->dev, &dev_attr_compress_wheel); | 222 | device_remove_file(&dev->intf->dev, &dev_attr_compress_wheel); |
223 | } | 223 | } |
224 | 224 | ||
225 | /* free data structures */ | 225 | /* free data structures */ |
226 | usb_free_urb(dev->interrupt_in_urb); | 226 | usb_free_urb(dev->interrupt_in_urb); |
227 | usb_free_urb(dev->interrupt_out_urb); | 227 | usb_free_urb(dev->interrupt_out_urb); |
228 | kfree(dev->ring_buffer); | 228 | kfree(dev->ring_buffer); |
229 | kfree(dev->interrupt_in_buffer); | 229 | kfree(dev->interrupt_in_buffer); |
230 | kfree(dev->interrupt_out_buffer); | 230 | kfree(dev->interrupt_out_buffer); |
231 | kfree(dev); | 231 | kfree(dev); |
232 | } | 232 | } |
233 | 233 | ||
234 | /** | 234 | /** |
235 | * usb_tranzport_interrupt_in_callback | 235 | * usb_tranzport_interrupt_in_callback |
236 | */ | 236 | */ |
237 | 237 | ||
238 | static void usb_tranzport_interrupt_in_callback(struct urb *urb) | 238 | static void usb_tranzport_interrupt_in_callback(struct urb *urb) |
239 | { | 239 | { |
240 | struct usb_tranzport *dev = urb->context; | 240 | struct usb_tranzport *dev = urb->context; |
241 | unsigned int next_ring_head; | 241 | unsigned int next_ring_head; |
242 | int retval = -1; | 242 | int retval = -1; |
243 | 243 | ||
244 | if (urb->status) { | 244 | if (urb->status) { |
245 | if (urb->status == -ENOENT || | 245 | if (urb->status == -ENOENT || |
246 | urb->status == -ECONNRESET || | 246 | urb->status == -ECONNRESET || |
247 | urb->status == -ESHUTDOWN) { | 247 | urb->status == -ESHUTDOWN) { |
248 | goto exit; | 248 | goto exit; |
249 | } else { | 249 | } else { |
250 | dbg_info(&dev->intf->dev, | 250 | dbg_info(&dev->intf->dev, |
251 | "%s: nonzero status received: %d\n", | 251 | "%s: nonzero status received: %d\n", |
252 | __func__, urb->status); | 252 | __func__, urb->status); |
253 | goto resubmit; /* maybe we can recover */ | 253 | goto resubmit; /* maybe we can recover */ |
254 | } | 254 | } |
255 | } | 255 | } |
256 | 256 | ||
257 | if (urb->actual_length != 8) { | 257 | if (urb->actual_length != 8) { |
258 | dev_warn(&dev->intf->dev, | 258 | dev_warn(&dev->intf->dev, |
259 | "Urb length was %d bytes!!" | 259 | "Urb length was %d bytes!!" |
260 | "Do something intelligent\n", | 260 | "Do something intelligent\n", |
261 | urb->actual_length); | 261 | urb->actual_length); |
262 | } else { | 262 | } else { |
263 | dbg_info(&dev->intf->dev, | 263 | dbg_info(&dev->intf->dev, |
264 | "%s: received: %02x%02x%02x%02x%02x%02x%02x%02x\n", | 264 | "%s: received: %02x%02x%02x%02x%02x%02x%02x%02x\n", |
265 | __func__, dev->interrupt_in_buffer[0], | 265 | __func__, dev->interrupt_in_buffer[0], |
266 | dev->interrupt_in_buffer[1], | 266 | dev->interrupt_in_buffer[1], |
267 | dev->interrupt_in_buffer[2], | 267 | dev->interrupt_in_buffer[2], |
268 | dev->interrupt_in_buffer[3], | 268 | dev->interrupt_in_buffer[3], |
269 | dev->interrupt_in_buffer[4], | 269 | dev->interrupt_in_buffer[4], |
270 | dev->interrupt_in_buffer[5], | 270 | dev->interrupt_in_buffer[5], |
271 | dev->interrupt_in_buffer[6], | 271 | dev->interrupt_in_buffer[6], |
272 | dev->interrupt_in_buffer[7]); | 272 | dev->interrupt_in_buffer[7]); |
273 | #if SUPPRESS_EXTRA_OFFLINE_EVENTS | 273 | #if SUPPRESS_EXTRA_OFFLINE_EVENTS |
274 | if (dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) | 274 | if (dev->offline == 2 && dev->interrupt_in_buffer[1] == 0xff) |
275 | goto resubmit; | 275 | goto resubmit; |
276 | if (dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { | 276 | if (dev->offline == 1 && dev->interrupt_in_buffer[1] == 0xff) { |
277 | dev->offline = 2; | 277 | dev->offline = 2; |
278 | goto resubmit; | 278 | goto resubmit; |
279 | } | 279 | } |
280 | 280 | ||
281 | /* Always pass one offline event up the stack */ | 281 | /* Always pass one offline event up the stack */ |
282 | if (dev->offline > 0 && dev->interrupt_in_buffer[1] != 0xff) | 282 | if (dev->offline > 0 && dev->interrupt_in_buffer[1] != 0xff) |
283 | dev->offline = 0; | 283 | dev->offline = 0; |
284 | if (dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) | 284 | if (dev->offline == 0 && dev->interrupt_in_buffer[1] == 0xff) |
285 | dev->offline = 1; | 285 | dev->offline = 1; |
286 | 286 | ||
287 | #endif /* SUPPRESS_EXTRA_OFFLINE_EVENTS */ | 287 | #endif /* SUPPRESS_EXTRA_OFFLINE_EVENTS */ |
288 | dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", | 288 | dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", |
289 | __func__, dev->ring_head, dev->ring_tail); | 289 | __func__, dev->ring_head, dev->ring_tail); |
290 | 290 | ||
291 | next_ring_head = (dev->ring_head + 1) % ring_buffer_size; | 291 | next_ring_head = (dev->ring_head + 1) % ring_buffer_size; |
292 | 292 | ||
293 | if (next_ring_head != dev->ring_tail) { | 293 | if (next_ring_head != dev->ring_tail) { |
294 | memcpy(&((*dev->ring_buffer)[dev->ring_head]), | 294 | memcpy(&((*dev->ring_buffer)[dev->ring_head]), |
295 | dev->interrupt_in_buffer, urb->actual_length); | 295 | dev->interrupt_in_buffer, urb->actual_length); |
296 | dev->ring_head = next_ring_head; | 296 | dev->ring_head = next_ring_head; |
297 | retval = 0; | 297 | retval = 0; |
298 | memset(dev->interrupt_in_buffer, 0, urb->actual_length); | 298 | memset(dev->interrupt_in_buffer, 0, urb->actual_length); |
299 | } else { | 299 | } else { |
300 | dev_warn(&dev->intf->dev, | 300 | dev_warn(&dev->intf->dev, |
301 | "Ring buffer overflow, %d bytes dropped\n", | 301 | "Ring buffer overflow, %d bytes dropped\n", |
302 | urb->actual_length); | 302 | urb->actual_length); |
303 | memset(dev->interrupt_in_buffer, 0, urb->actual_length); | 303 | memset(dev->interrupt_in_buffer, 0, urb->actual_length); |
304 | } | 304 | } |
305 | } | 305 | } |
306 | 306 | ||
307 | resubmit: | 307 | resubmit: |
308 | /* resubmit if we're still running */ | 308 | /* resubmit if we're still running */ |
309 | if (dev->interrupt_in_running && dev->intf) { | 309 | if (dev->interrupt_in_running && dev->intf) { |
310 | retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); | 310 | retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); |
311 | if (retval) | 311 | if (retval) |
312 | dev_err(&dev->intf->dev, | 312 | dev_err(&dev->intf->dev, |
313 | "usb_submit_urb failed (%d)\n", retval); | 313 | "usb_submit_urb failed (%d)\n", retval); |
314 | } | 314 | } |
315 | 315 | ||
316 | exit: | 316 | exit: |
317 | dev->interrupt_in_done = 1; | 317 | dev->interrupt_in_done = 1; |
318 | wake_up_interruptible(&dev->read_wait); | 318 | wake_up_interruptible(&dev->read_wait); |
319 | } | 319 | } |
320 | 320 | ||
321 | /** | 321 | /** |
322 | * usb_tranzport_interrupt_out_callback | 322 | * usb_tranzport_interrupt_out_callback |
323 | */ | 323 | */ |
324 | static void usb_tranzport_interrupt_out_callback(struct urb *urb) | 324 | static void usb_tranzport_interrupt_out_callback(struct urb *urb) |
325 | { | 325 | { |
326 | struct usb_tranzport *dev = urb->context; | 326 | struct usb_tranzport *dev = urb->context; |
327 | /* sync/async unlink faults aren't errors */ | 327 | /* sync/async unlink faults aren't errors */ |
328 | if (urb->status && !(urb->status == -ENOENT || | 328 | if (urb->status && !(urb->status == -ENOENT || |
329 | urb->status == -ECONNRESET || | 329 | urb->status == -ECONNRESET || |
330 | urb->status == -ESHUTDOWN)) | 330 | urb->status == -ESHUTDOWN)) |
331 | dbg_info(&dev->intf->dev, | 331 | dbg_info(&dev->intf->dev, |
332 | "%s - nonzero write interrupt status received: %d\n", | 332 | "%s - nonzero write interrupt status received: %d\n", |
333 | __func__, urb->status); | 333 | __func__, urb->status); |
334 | 334 | ||
335 | dev->interrupt_out_busy = 0; | 335 | dev->interrupt_out_busy = 0; |
336 | wake_up_interruptible(&dev->write_wait); | 336 | wake_up_interruptible(&dev->write_wait); |
337 | } | 337 | } |
338 | /** | 338 | /** |
339 | * usb_tranzport_open | 339 | * usb_tranzport_open |
340 | */ | 340 | */ |
341 | static int usb_tranzport_open(struct inode *inode, struct file *file) | 341 | static int usb_tranzport_open(struct inode *inode, struct file *file) |
342 | { | 342 | { |
343 | struct usb_tranzport *dev; | 343 | struct usb_tranzport *dev; |
344 | int subminor; | 344 | int subminor; |
345 | int retval = 0; | 345 | int retval = 0; |
346 | struct usb_interface *interface; | 346 | struct usb_interface *interface; |
347 | 347 | ||
348 | nonseekable_open(inode, file); | 348 | nonseekable_open(inode, file); |
349 | subminor = iminor(inode); | 349 | subminor = iminor(inode); |
350 | 350 | ||
351 | mutex_lock(&disconnect_mutex); | 351 | mutex_lock(&disconnect_mutex); |
352 | 352 | ||
353 | interface = usb_find_interface(&usb_tranzport_driver, subminor); | 353 | interface = usb_find_interface(&usb_tranzport_driver, subminor); |
354 | 354 | ||
355 | if (!interface) { | 355 | if (!interface) { |
356 | err("%s - error, can't find device for minor %d\n", | 356 | err("%s - error, can't find device for minor %d\n", |
357 | __func__, subminor); | 357 | __func__, subminor); |
358 | retval = -ENODEV; | 358 | retval = -ENODEV; |
359 | goto unlock_disconnect_exit; | 359 | goto unlock_disconnect_exit; |
360 | } | 360 | } |
361 | 361 | ||
362 | dev = usb_get_intfdata(interface); | 362 | dev = usb_get_intfdata(interface); |
363 | 363 | ||
364 | if (!dev) { | 364 | if (!dev) { |
365 | retval = -ENODEV; | 365 | retval = -ENODEV; |
366 | goto unlock_disconnect_exit; | 366 | goto unlock_disconnect_exit; |
367 | } | 367 | } |
368 | 368 | ||
369 | /* lock this device */ | 369 | /* lock this device */ |
370 | if (mutex_lock_interruptible(&dev->mtx)) { | 370 | if (mutex_lock_interruptible(&dev->mtx)) { |
371 | retval = -ERESTARTSYS; | 371 | retval = -ERESTARTSYS; |
372 | goto unlock_disconnect_exit; | 372 | goto unlock_disconnect_exit; |
373 | } | 373 | } |
374 | 374 | ||
375 | /* allow opening only once */ | 375 | /* allow opening only once */ |
376 | if (dev->open_count) { | 376 | if (dev->open_count) { |
377 | retval = -EBUSY; | 377 | retval = -EBUSY; |
378 | goto unlock_exit; | 378 | goto unlock_exit; |
379 | } | 379 | } |
380 | dev->open_count = 1; | 380 | dev->open_count = 1; |
381 | 381 | ||
382 | /* initialize in direction */ | 382 | /* initialize in direction */ |
383 | dev->ring_head = 0; | 383 | dev->ring_head = 0; |
384 | dev->ring_tail = 0; | 384 | dev->ring_tail = 0; |
385 | usb_fill_int_urb(dev->interrupt_in_urb, | 385 | usb_fill_int_urb(dev->interrupt_in_urb, |
386 | interface_to_usbdev(interface), | 386 | interface_to_usbdev(interface), |
387 | usb_rcvintpipe(interface_to_usbdev(interface), | 387 | usb_rcvintpipe(interface_to_usbdev(interface), |
388 | dev->interrupt_in_endpoint-> | 388 | dev->interrupt_in_endpoint-> |
389 | bEndpointAddress), | 389 | bEndpointAddress), |
390 | dev->interrupt_in_buffer, | 390 | dev->interrupt_in_buffer, |
391 | dev->interrupt_in_endpoint_size, | 391 | dev->interrupt_in_endpoint_size, |
392 | usb_tranzport_interrupt_in_callback, dev, | 392 | usb_tranzport_interrupt_in_callback, dev, |
393 | dev->interrupt_in_interval); | 393 | dev->interrupt_in_interval); |
394 | 394 | ||
395 | dev->interrupt_in_running = 1; | 395 | dev->interrupt_in_running = 1; |
396 | dev->interrupt_in_done = 0; | 396 | dev->interrupt_in_done = 0; |
397 | dev->enable = 1; | 397 | dev->enable = 1; |
398 | dev->offline = 0; | 398 | dev->offline = 0; |
399 | dev->compress_wheel = 1; | 399 | dev->compress_wheel = 1; |
400 | 400 | ||
401 | retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); | 401 | retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); |
402 | if (retval) { | 402 | if (retval) { |
403 | dev_err(&interface->dev, | 403 | dev_err(&interface->dev, |
404 | "Couldn't submit interrupt_in_urb %d\n", retval); | 404 | "Couldn't submit interrupt_in_urb %d\n", retval); |
405 | dev->interrupt_in_running = 0; | 405 | dev->interrupt_in_running = 0; |
406 | dev->open_count = 0; | 406 | dev->open_count = 0; |
407 | goto unlock_exit; | 407 | goto unlock_exit; |
408 | } | 408 | } |
409 | 409 | ||
410 | /* save device in the file's private structure */ | 410 | /* save device in the file's private structure */ |
411 | file->private_data = dev; | 411 | file->private_data = dev; |
412 | 412 | ||
413 | unlock_exit: | 413 | unlock_exit: |
414 | mutex_unlock(&dev->mtx); | 414 | mutex_unlock(&dev->mtx); |
415 | 415 | ||
416 | unlock_disconnect_exit: | 416 | unlock_disconnect_exit: |
417 | mutex_unlock(&disconnect_mutex); | 417 | mutex_unlock(&disconnect_mutex); |
418 | 418 | ||
419 | return retval; | 419 | return retval; |
420 | } | 420 | } |
421 | 421 | ||
422 | /** | 422 | /** |
423 | * usb_tranzport_release | 423 | * usb_tranzport_release |
424 | */ | 424 | */ |
425 | static int usb_tranzport_release(struct inode *inode, struct file *file) | 425 | static int usb_tranzport_release(struct inode *inode, struct file *file) |
426 | { | 426 | { |
427 | struct usb_tranzport *dev; | 427 | struct usb_tranzport *dev; |
428 | int retval = 0; | 428 | int retval = 0; |
429 | 429 | ||
430 | dev = file->private_data; | 430 | dev = file->private_data; |
431 | 431 | ||
432 | if (dev == NULL) { | 432 | if (dev == NULL) { |
433 | retval = -ENODEV; | 433 | retval = -ENODEV; |
434 | goto exit; | 434 | goto exit; |
435 | } | 435 | } |
436 | 436 | ||
437 | if (mutex_lock_interruptible(&dev->mtx)) { | 437 | if (mutex_lock_interruptible(&dev->mtx)) { |
438 | retval = -ERESTARTSYS; | 438 | retval = -ERESTARTSYS; |
439 | goto exit; | 439 | goto exit; |
440 | } | 440 | } |
441 | 441 | ||
442 | if (dev->open_count != 1) { | 442 | if (dev->open_count != 1) { |
443 | retval = -ENODEV; | 443 | retval = -ENODEV; |
444 | goto unlock_exit; | 444 | goto unlock_exit; |
445 | } | 445 | } |
446 | 446 | ||
447 | if (dev->intf == NULL) { | 447 | if (dev->intf == NULL) { |
448 | /* the device was unplugged before the file was released */ | 448 | /* the device was unplugged before the file was released */ |
449 | mutex_unlock(&dev->mtx); | 449 | mutex_unlock(&dev->mtx); |
450 | /* unlock here as usb_tranzport_delete frees dev */ | 450 | /* unlock here as usb_tranzport_delete frees dev */ |
451 | usb_tranzport_delete(dev); | 451 | usb_tranzport_delete(dev); |
452 | retval = -ENODEV; | 452 | retval = -ENODEV; |
453 | goto exit; | 453 | goto exit; |
454 | } | 454 | } |
455 | 455 | ||
456 | /* wait until write transfer is finished */ | 456 | /* wait until write transfer is finished */ |
457 | if (dev->interrupt_out_busy) | 457 | if (dev->interrupt_out_busy) |
458 | wait_event_interruptible_timeout(dev->write_wait, | 458 | wait_event_interruptible_timeout(dev->write_wait, |
459 | !dev->interrupt_out_busy, | 459 | !dev->interrupt_out_busy, |
460 | 2 * HZ); | 460 | 2 * HZ); |
461 | usb_tranzport_abort_transfers(dev); | 461 | usb_tranzport_abort_transfers(dev); |
462 | dev->open_count = 0; | 462 | dev->open_count = 0; |
463 | 463 | ||
464 | unlock_exit: | 464 | unlock_exit: |
465 | mutex_unlock(&dev->mtx); | 465 | mutex_unlock(&dev->mtx); |
466 | 466 | ||
467 | exit: | 467 | exit: |
468 | return retval; | 468 | return retval; |
469 | } | 469 | } |
470 | 470 | ||
471 | /** | 471 | /** |
472 | * usb_tranzport_poll | 472 | * usb_tranzport_poll |
473 | */ | 473 | */ |
474 | static unsigned int usb_tranzport_poll(struct file *file, poll_table * wait) | 474 | static unsigned int usb_tranzport_poll(struct file *file, poll_table *wait) |
475 | { | 475 | { |
476 | struct usb_tranzport *dev; | 476 | struct usb_tranzport *dev; |
477 | unsigned int mask = 0; | 477 | unsigned int mask = 0; |
478 | dev = file->private_data; | 478 | dev = file->private_data; |
479 | poll_wait(file, &dev->read_wait, wait); | 479 | poll_wait(file, &dev->read_wait, wait); |
480 | poll_wait(file, &dev->write_wait, wait); | 480 | poll_wait(file, &dev->write_wait, wait); |
481 | if (dev->ring_head != dev->ring_tail) | 481 | if (dev->ring_head != dev->ring_tail) |
482 | mask |= POLLIN | POLLRDNORM; | 482 | mask |= POLLIN | POLLRDNORM; |
483 | if (!dev->interrupt_out_busy) | 483 | if (!dev->interrupt_out_busy) |
484 | mask |= POLLOUT | POLLWRNORM; | 484 | mask |= POLLOUT | POLLWRNORM; |
485 | return mask; | 485 | return mask; |
486 | } | 486 | } |
487 | /** | 487 | /** |
488 | * usb_tranzport_read | 488 | * usb_tranzport_read |
489 | */ | 489 | */ |
490 | 490 | ||
491 | static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, | 491 | static ssize_t usb_tranzport_read(struct file *file, char __user *buffer, |
492 | size_t count, loff_t *ppos) | 492 | size_t count, loff_t *ppos) |
493 | { | 493 | { |
494 | struct usb_tranzport *dev; | 494 | struct usb_tranzport *dev; |
495 | int retval = 0; | 495 | int retval = 0; |
496 | #if BUFFERED_READS | 496 | #if BUFFERED_READS |
497 | int c = 0; | 497 | int c = 0; |
498 | #endif | 498 | #endif |
499 | #if COMPRESS_WHEEL_EVENTS | 499 | #if COMPRESS_WHEEL_EVENTS |
500 | signed char oldwheel; | 500 | signed char oldwheel; |
501 | signed char newwheel; | 501 | signed char newwheel; |
502 | int cancompress = 1; | 502 | int cancompress = 1; |
503 | int next_tail; | 503 | int next_tail; |
504 | #endif | 504 | #endif |
505 | 505 | ||
506 | /* do I have such a thing as a null event? */ | 506 | /* do I have such a thing as a null event? */ |
507 | 507 | ||
508 | dev = file->private_data; | 508 | dev = file->private_data; |
509 | 509 | ||
510 | /* verify that we actually have some data to read */ | 510 | /* verify that we actually have some data to read */ |
511 | if (count == 0) | 511 | if (count == 0) |
512 | goto exit; | 512 | goto exit; |
513 | 513 | ||
514 | /* lock this object */ | 514 | /* lock this object */ |
515 | if (mutex_lock_interruptible(&dev->mtx)) { | 515 | if (mutex_lock_interruptible(&dev->mtx)) { |
516 | retval = -ERESTARTSYS; | 516 | retval = -ERESTARTSYS; |
517 | goto exit; | 517 | goto exit; |
518 | } | 518 | } |
519 | 519 | ||
520 | /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { | 520 | /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { |
521 | retval = -ENODEV; | 521 | retval = -ENODEV; |
522 | err("No device or device unplugged %d\n", retval); | 522 | err("No device or device unplugged %d\n", retval); |
523 | goto unlock_exit; | 523 | goto unlock_exit; |
524 | } | 524 | } |
525 | 525 | ||
526 | while (dev->ring_head == dev->ring_tail) { | 526 | while (dev->ring_head == dev->ring_tail) { |
527 | 527 | ||
528 | if (file->f_flags & O_NONBLOCK) { | 528 | if (file->f_flags & O_NONBLOCK) { |
529 | retval = -EAGAIN; | 529 | retval = -EAGAIN; |
530 | goto unlock_exit; | 530 | goto unlock_exit; |
531 | } | 531 | } |
532 | /* tiny race - FIXME: make atomic? */ | 532 | /* tiny race - FIXME: make atomic? */ |
533 | /* atomic_cmp_exchange(&dev->interrupt_in_done,0,0); */ | 533 | /* atomic_cmp_exchange(&dev->interrupt_in_done,0,0); */ |
534 | dev->interrupt_in_done = 0; | 534 | dev->interrupt_in_done = 0; |
535 | retval = wait_event_interruptible(dev->read_wait, | 535 | retval = wait_event_interruptible(dev->read_wait, |
536 | dev->interrupt_in_done); | 536 | dev->interrupt_in_done); |
537 | if (retval < 0) | 537 | if (retval < 0) |
538 | goto unlock_exit; | 538 | goto unlock_exit; |
539 | } | 539 | } |
540 | 540 | ||
541 | dbg_info(&dev->intf->dev, | 541 | dbg_info(&dev->intf->dev, |
542 | "%s: copying to userspace: " | 542 | "%s: copying to userspace: " |
543 | "%02x%02x%02x%02x%02x%02x%02x%02x\n", | 543 | "%02x%02x%02x%02x%02x%02x%02x%02x\n", |
544 | __func__, | 544 | __func__, |
545 | (*dev->ring_buffer)[dev->ring_tail].cmd[0], | 545 | (*dev->ring_buffer)[dev->ring_tail].cmd[0], |
546 | (*dev->ring_buffer)[dev->ring_tail].cmd[1], | 546 | (*dev->ring_buffer)[dev->ring_tail].cmd[1], |
547 | (*dev->ring_buffer)[dev->ring_tail].cmd[2], | 547 | (*dev->ring_buffer)[dev->ring_tail].cmd[2], |
548 | (*dev->ring_buffer)[dev->ring_tail].cmd[3], | 548 | (*dev->ring_buffer)[dev->ring_tail].cmd[3], |
549 | (*dev->ring_buffer)[dev->ring_tail].cmd[4], | 549 | (*dev->ring_buffer)[dev->ring_tail].cmd[4], |
550 | (*dev->ring_buffer)[dev->ring_tail].cmd[5], | 550 | (*dev->ring_buffer)[dev->ring_tail].cmd[5], |
551 | (*dev->ring_buffer)[dev->ring_tail].cmd[6], | 551 | (*dev->ring_buffer)[dev->ring_tail].cmd[6], |
552 | (*dev->ring_buffer)[dev->ring_tail].cmd[7]); | 552 | (*dev->ring_buffer)[dev->ring_tail].cmd[7]); |
553 | 553 | ||
554 | #if BUFFERED_READS | 554 | #if BUFFERED_READS |
555 | c = 0; | 555 | c = 0; |
556 | while ((c < count) && (dev->ring_tail != dev->ring_head)) { | 556 | while ((c < count) && (dev->ring_tail != dev->ring_head)) { |
557 | 557 | ||
558 | #if COMPRESS_WHEEL_EVENTS | 558 | #if COMPRESS_WHEEL_EVENTS |
559 | next_tail = (dev->ring_tail+1) % ring_buffer_size; | 559 | next_tail = (dev->ring_tail+1) % ring_buffer_size; |
560 | if (dev->compress_wheel) | 560 | if (dev->compress_wheel) |
561 | cancompress = 1; | 561 | cancompress = 1; |
562 | while (dev->ring_head != next_tail && cancompress == 1) { | 562 | while (dev->ring_head != next_tail && cancompress == 1) { |
563 | newwheel = (*dev->ring_buffer)[next_tail].cmd[6]; | 563 | newwheel = (*dev->ring_buffer)[next_tail].cmd[6]; |
564 | oldwheel = (*dev->ring_buffer)[dev->ring_tail].cmd[6]; | 564 | oldwheel = (*dev->ring_buffer)[dev->ring_tail].cmd[6]; |
565 | /* if both are wheel events, and | 565 | /* if both are wheel events, and |
566 | no buttons have changes (FIXME, do I have to check?), | 566 | no buttons have changes (FIXME, do I have to check?), |
567 | and we are the same sign, we can compress +- 7F | 567 | and we are the same sign, we can compress +- 7F |
568 | */ | 568 | */ |
569 | dbg_info(&dev->intf->dev, | 569 | dbg_info(&dev->intf->dev, |
570 | "%s: trying to compress: " | 570 | "%s: trying to compress: " |
571 | "%02x%02x%02x%02x%02x%02x%02x%02x\n", | 571 | "%02x%02x%02x%02x%02x%02x%02x%02x\n", |
572 | __func__, | 572 | __func__, |
573 | (*dev->ring_buffer)[dev->ring_tail].cmd[0], | 573 | (*dev->ring_buffer)[dev->ring_tail].cmd[0], |
574 | (*dev->ring_buffer)[dev->ring_tail].cmd[1], | 574 | (*dev->ring_buffer)[dev->ring_tail].cmd[1], |
575 | (*dev->ring_buffer)[dev->ring_tail].cmd[2], | 575 | (*dev->ring_buffer)[dev->ring_tail].cmd[2], |
576 | (*dev->ring_buffer)[dev->ring_tail].cmd[3], | 576 | (*dev->ring_buffer)[dev->ring_tail].cmd[3], |
577 | (*dev->ring_buffer)[dev->ring_tail].cmd[4], | 577 | (*dev->ring_buffer)[dev->ring_tail].cmd[4], |
578 | (*dev->ring_buffer)[dev->ring_tail].cmd[5], | 578 | (*dev->ring_buffer)[dev->ring_tail].cmd[5], |
579 | (*dev->ring_buffer)[dev->ring_tail].cmd[6], | 579 | (*dev->ring_buffer)[dev->ring_tail].cmd[6], |
580 | (*dev->ring_buffer)[dev->ring_tail].cmd[7]); | 580 | (*dev->ring_buffer)[dev->ring_tail].cmd[7]); |
581 | 581 | ||
582 | if (((*dev->ring_buffer)[dev->ring_tail].cmd[6] != 0 && | 582 | if (((*dev->ring_buffer)[dev->ring_tail].cmd[6] != 0 && |
583 | (*dev->ring_buffer)[next_tail].cmd[6] != 0) && | 583 | (*dev->ring_buffer)[next_tail].cmd[6] != 0) && |
584 | ((newwheel > 0 && oldwheel > 0) || | 584 | ((newwheel > 0 && oldwheel > 0) || |
585 | (newwheel < 0 && oldwheel < 0)) && | 585 | (newwheel < 0 && oldwheel < 0)) && |
586 | ((*dev->ring_buffer)[dev->ring_tail].cmd[2] == | 586 | ((*dev->ring_buffer)[dev->ring_tail].cmd[2] == |
587 | (*dev->ring_buffer)[next_tail].cmd[2]) && | 587 | (*dev->ring_buffer)[next_tail].cmd[2]) && |
588 | ((*dev->ring_buffer)[dev->ring_tail].cmd[3] == | 588 | ((*dev->ring_buffer)[dev->ring_tail].cmd[3] == |
589 | (*dev->ring_buffer)[next_tail].cmd[3]) && | 589 | (*dev->ring_buffer)[next_tail].cmd[3]) && |
590 | ((*dev->ring_buffer)[dev->ring_tail].cmd[4] == | 590 | ((*dev->ring_buffer)[dev->ring_tail].cmd[4] == |
591 | (*dev->ring_buffer)[next_tail].cmd[4]) && | 591 | (*dev->ring_buffer)[next_tail].cmd[4]) && |
592 | ((*dev->ring_buffer)[dev->ring_tail].cmd[5] == | 592 | ((*dev->ring_buffer)[dev->ring_tail].cmd[5] == |
593 | (*dev->ring_buffer)[next_tail].cmd[5])) { | 593 | (*dev->ring_buffer)[next_tail].cmd[5])) { |
594 | dbg_info(&dev->intf->dev, | 594 | dbg_info(&dev->intf->dev, |
595 | "%s: should compress: " | 595 | "%s: should compress: " |
596 | "%02x%02x%02x%02x%02x%02x%02x%02x\n", | 596 | "%02x%02x%02x%02x%02x%02x%02x%02x\n", |
597 | __func__, | 597 | __func__, |
598 | (*dev->ring_buffer)[dev->ring_tail]. | 598 | (*dev->ring_buffer)[dev->ring_tail]. |
599 | cmd[0], | 599 | cmd[0], |
600 | (*dev->ring_buffer)[dev->ring_tail]. | 600 | (*dev->ring_buffer)[dev->ring_tail]. |
601 | cmd[1], | 601 | cmd[1], |
602 | (*dev->ring_buffer)[dev->ring_tail]. | 602 | (*dev->ring_buffer)[dev->ring_tail]. |
603 | cmd[2], | 603 | cmd[2], |
604 | (*dev->ring_buffer)[dev->ring_tail]. | 604 | (*dev->ring_buffer)[dev->ring_tail]. |
605 | cmd[3], | 605 | cmd[3], |
606 | (*dev->ring_buffer)[dev->ring_tail]. | 606 | (*dev->ring_buffer)[dev->ring_tail]. |
607 | cmd[4], | 607 | cmd[4], |
608 | (*dev->ring_buffer)[dev->ring_tail]. | 608 | (*dev->ring_buffer)[dev->ring_tail]. |
609 | cmd[5], | 609 | cmd[5], |
610 | (*dev->ring_buffer)[dev->ring_tail]. | 610 | (*dev->ring_buffer)[dev->ring_tail]. |
611 | cmd[6], | 611 | cmd[6], |
612 | (*dev->ring_buffer)[dev->ring_tail]. | 612 | (*dev->ring_buffer)[dev->ring_tail]. |
613 | cmd[7]); | 613 | cmd[7]); |
614 | newwheel += oldwheel; | 614 | newwheel += oldwheel; |
615 | if (oldwheel > 0 && !(newwheel > 0)) { | 615 | if (oldwheel > 0 && !(newwheel > 0)) { |
616 | newwheel = 0x7f; | 616 | newwheel = 0x7f; |
617 | cancompress = 0; | 617 | cancompress = 0; |
618 | } | 618 | } |
619 | if (oldwheel < 0 && !(newwheel < 0)) { | 619 | if (oldwheel < 0 && !(newwheel < 0)) { |
620 | newwheel = 0x80; | 620 | newwheel = 0x80; |
621 | cancompress = 0; | 621 | cancompress = 0; |
622 | } | 622 | } |
623 | 623 | ||
624 | (*dev->ring_buffer)[next_tail].cmd[6] = | 624 | (*dev->ring_buffer)[next_tail].cmd[6] = |
625 | newwheel; | 625 | newwheel; |
626 | dev->ring_tail = next_tail; | 626 | dev->ring_tail = next_tail; |
627 | next_tail = | 627 | next_tail = |
628 | (dev->ring_tail + 1) % ring_buffer_size; | 628 | (dev->ring_tail + 1) % ring_buffer_size; |
629 | } else { | 629 | } else { |
630 | cancompress = 0; | 630 | cancompress = 0; |
631 | } | 631 | } |
632 | } | 632 | } |
633 | #endif /* COMPRESS_WHEEL_EVENTS */ | 633 | #endif /* COMPRESS_WHEEL_EVENTS */ |
634 | if (copy_to_user( | 634 | if (copy_to_user( |
635 | &buffer[c], | 635 | &buffer[c], |
636 | &(*dev->ring_buffer)[dev->ring_tail], 8)) { | 636 | &(*dev->ring_buffer)[dev->ring_tail], 8)) { |
637 | retval = -EFAULT; | 637 | retval = -EFAULT; |
638 | goto unlock_exit; | 638 | goto unlock_exit; |
639 | } | 639 | } |
640 | dev->ring_tail = (dev->ring_tail + 1) % ring_buffer_size; | 640 | dev->ring_tail = (dev->ring_tail + 1) % ring_buffer_size; |
641 | c += 8; | 641 | c += 8; |
642 | dbg_info(&dev->intf->dev, | 642 | dbg_info(&dev->intf->dev, |
643 | "%s: head, tail are %x, %x\n", | 643 | "%s: head, tail are %x, %x\n", |
644 | __func__, dev->ring_head, dev->ring_tail); | 644 | __func__, dev->ring_head, dev->ring_tail); |
645 | } | 645 | } |
646 | retval = c; | 646 | retval = c; |
647 | 647 | ||
648 | #else | 648 | #else |
649 | /* if (copy_to_user(buffer, &(*dev->ring_buffer)[dev->ring_tail], 8)) { */ | 649 | /* if (copy_to_user(buffer, &(*dev->ring_buffer)[dev->ring_tail], 8)) { */ |
650 | retval = -EFAULT; | 650 | retval = -EFAULT; |
651 | goto unlock_exit; | 651 | goto unlock_exit; |
652 | } | 652 | } |
653 | 653 | ||
654 | dev->ring_tail = (dev->ring_tail + 1) % ring_buffer_size; | 654 | dev->ring_tail = (dev->ring_tail + 1) % ring_buffer_size; |
655 | dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", | 655 | dbg_info(&dev->intf->dev, "%s: head, tail are %x, %x\n", |
656 | __func__, dev->ring_head, dev->ring_tail); | 656 | __func__, dev->ring_head, dev->ring_tail); |
657 | 657 | ||
658 | retval = 8; | 658 | retval = 8; |
659 | #endif /* BUFFERED_READS */ | 659 | #endif /* BUFFERED_READS */ |
660 | 660 | ||
661 | unlock_exit: | 661 | unlock_exit: |
662 | /* unlock the device */ | 662 | /* unlock the device */ |
663 | mutex_unlock(&dev->mtx); | 663 | mutex_unlock(&dev->mtx); |
664 | 664 | ||
665 | exit: | 665 | exit: |
666 | return retval; | 666 | return retval; |
667 | } | 667 | } |
668 | 668 | ||
669 | /** | 669 | /** |
670 | * usb_tranzport_write | 670 | * usb_tranzport_write |
671 | */ | 671 | */ |
672 | static ssize_t usb_tranzport_write(struct file *file, | 672 | static ssize_t usb_tranzport_write(struct file *file, |
673 | const char __user *buffer, size_t count, | 673 | const char __user *buffer, size_t count, |
674 | loff_t *ppos) | 674 | loff_t *ppos) |
675 | { | 675 | { |
676 | struct usb_tranzport *dev; | 676 | struct usb_tranzport *dev; |
677 | size_t bytes_to_write; | 677 | size_t bytes_to_write; |
678 | int retval = 0; | 678 | int retval = 0; |
679 | 679 | ||
680 | dev = file->private_data; | 680 | dev = file->private_data; |
681 | 681 | ||
682 | /* verify that we actually have some data to write */ | 682 | /* verify that we actually have some data to write */ |
683 | if (count == 0) | 683 | if (count == 0) |
684 | goto exit; | 684 | goto exit; |
685 | 685 | ||
686 | /* lock this object */ | 686 | /* lock this object */ |
687 | if (mutex_lock_interruptible(&dev->mtx)) { | 687 | if (mutex_lock_interruptible(&dev->mtx)) { |
688 | retval = -ERESTARTSYS; | 688 | retval = -ERESTARTSYS; |
689 | goto exit; | 689 | goto exit; |
690 | } | 690 | } |
691 | /* verify that the device wasn't unplugged */ | 691 | /* verify that the device wasn't unplugged */ |
692 | if (dev->intf == NULL) { | 692 | if (dev->intf == NULL) { |
693 | retval = -ENODEV; | 693 | retval = -ENODEV; |
694 | err("No device or device unplugged %d\n", retval); | 694 | err("No device or device unplugged %d\n", retval); |
695 | goto unlock_exit; | 695 | goto unlock_exit; |
696 | } | 696 | } |
697 | 697 | ||
698 | /* wait until previous transfer is finished */ | 698 | /* wait until previous transfer is finished */ |
699 | if (dev->interrupt_out_busy) { | 699 | if (dev->interrupt_out_busy) { |
700 | if (file->f_flags & O_NONBLOCK) { | 700 | if (file->f_flags & O_NONBLOCK) { |
701 | retval = -EAGAIN; | 701 | retval = -EAGAIN; |
702 | goto unlock_exit; | 702 | goto unlock_exit; |
703 | } | 703 | } |
704 | retval = wait_event_interruptible(dev->write_wait, | 704 | retval = wait_event_interruptible(dev->write_wait, |
705 | !dev->interrupt_out_busy); | 705 | !dev->interrupt_out_busy); |
706 | if (retval < 0) | 706 | if (retval < 0) |
707 | goto unlock_exit; | 707 | goto unlock_exit; |
708 | } | 708 | } |
709 | 709 | ||
710 | /* write the data into interrupt_out_buffer from userspace */ | 710 | /* write the data into interrupt_out_buffer from userspace */ |
711 | bytes_to_write = min(count, | 711 | bytes_to_write = min(count, |
712 | write_buffer_size * | 712 | write_buffer_size * |
713 | dev->interrupt_out_endpoint_size); | 713 | dev->interrupt_out_endpoint_size); |
714 | if (bytes_to_write < count) | 714 | if (bytes_to_write < count) |
715 | dev_warn(&dev->intf->dev, | 715 | dev_warn(&dev->intf->dev, |
716 | "Write buffer overflow, %zd bytes dropped\n", | 716 | "Write buffer overflow, %zd bytes dropped\n", |
717 | count - bytes_to_write); | 717 | count - bytes_to_write); |
718 | 718 | ||
719 | dbg_info(&dev->intf->dev, | 719 | dbg_info(&dev->intf->dev, |
720 | "%s: count = %zd, bytes_to_write = %zd\n", __func__, | 720 | "%s: count = %zd, bytes_to_write = %zd\n", __func__, |
721 | count, bytes_to_write); | 721 | count, bytes_to_write); |
722 | 722 | ||
723 | if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { | 723 | if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { |
724 | retval = -EFAULT; | 724 | retval = -EFAULT; |
725 | goto unlock_exit; | 725 | goto unlock_exit; |
726 | } | 726 | } |
727 | 727 | ||
728 | if (dev->interrupt_out_endpoint == NULL) { | 728 | if (dev->interrupt_out_endpoint == NULL) { |
729 | err("Endpoint should not be be null!\n"); | 729 | err("Endpoint should not be be null!\n"); |
730 | goto unlock_exit; | 730 | goto unlock_exit; |
731 | } | 731 | } |
732 | 732 | ||
733 | /* send off the urb */ | 733 | /* send off the urb */ |
734 | usb_fill_int_urb(dev->interrupt_out_urb, | 734 | usb_fill_int_urb(dev->interrupt_out_urb, |
735 | interface_to_usbdev(dev->intf), | 735 | interface_to_usbdev(dev->intf), |
736 | usb_sndintpipe(interface_to_usbdev(dev->intf), | 736 | usb_sndintpipe(interface_to_usbdev(dev->intf), |
737 | dev->interrupt_out_endpoint-> | 737 | dev->interrupt_out_endpoint-> |
738 | bEndpointAddress), | 738 | bEndpointAddress), |
739 | dev->interrupt_out_buffer, bytes_to_write, | 739 | dev->interrupt_out_buffer, bytes_to_write, |
740 | usb_tranzport_interrupt_out_callback, dev, | 740 | usb_tranzport_interrupt_out_callback, dev, |
741 | dev->interrupt_out_interval); | 741 | dev->interrupt_out_interval); |
742 | 742 | ||
743 | dev->interrupt_out_busy = 1; | 743 | dev->interrupt_out_busy = 1; |
744 | wmb(); | 744 | wmb(); |
745 | 745 | ||
746 | retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); | 746 | retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); |
747 | if (retval) { | 747 | if (retval) { |
748 | dev->interrupt_out_busy = 0; | 748 | dev->interrupt_out_busy = 0; |
749 | err("Couldn't submit interrupt_out_urb %d\n", retval); | 749 | err("Couldn't submit interrupt_out_urb %d\n", retval); |
750 | goto unlock_exit; | 750 | goto unlock_exit; |
751 | } | 751 | } |
752 | retval = bytes_to_write; | 752 | retval = bytes_to_write; |
753 | 753 | ||
754 | unlock_exit: | 754 | unlock_exit: |
755 | /* unlock the device */ | 755 | /* unlock the device */ |
756 | mutex_unlock(&dev->mtx); | 756 | mutex_unlock(&dev->mtx); |
757 | 757 | ||
758 | exit: | 758 | exit: |
759 | return retval; | 759 | return retval; |
760 | } | 760 | } |
761 | 761 | ||
762 | /* file operations needed when we register this driver */ | 762 | /* file operations needed when we register this driver */ |
763 | static const struct file_operations usb_tranzport_fops = { | 763 | static const struct file_operations usb_tranzport_fops = { |
764 | .owner = THIS_MODULE, | 764 | .owner = THIS_MODULE, |
765 | .read = usb_tranzport_read, | 765 | .read = usb_tranzport_read, |
766 | .write = usb_tranzport_write, | 766 | .write = usb_tranzport_write, |
767 | .open = usb_tranzport_open, | 767 | .open = usb_tranzport_open, |
768 | .release = usb_tranzport_release, | 768 | .release = usb_tranzport_release, |
769 | .poll = usb_tranzport_poll, | 769 | .poll = usb_tranzport_poll, |
770 | .llseek = no_llseek, | 770 | .llseek = no_llseek, |
771 | }; | 771 | }; |
772 | 772 | ||
773 | /* | 773 | /* |
774 | * usb class driver info in order to get a minor number from the usb core, | 774 | * usb class driver info in order to get a minor number from the usb core, |
775 | * and to have the device registered with the driver core | 775 | * and to have the device registered with the driver core |
776 | */ | 776 | */ |
777 | static struct usb_class_driver usb_tranzport_class = { | 777 | static struct usb_class_driver usb_tranzport_class = { |
778 | .name = "tranzport%d", | 778 | .name = "tranzport%d", |
779 | .fops = &usb_tranzport_fops, | 779 | .fops = &usb_tranzport_fops, |
780 | .minor_base = USB_TRANZPORT_MINOR_BASE, | 780 | .minor_base = USB_TRANZPORT_MINOR_BASE, |
781 | }; | 781 | }; |
782 | 782 | ||
783 | /** | 783 | /** |
784 | * usb_tranzport_probe | 784 | * usb_tranzport_probe |
785 | * | 785 | * |
786 | * Called by the usb core when a new device is connected that it thinks | 786 | * Called by the usb core when a new device is connected that it thinks |
787 | * this driver might be interested in. | 787 | * this driver might be interested in. |
788 | */ | 788 | */ |
789 | static int usb_tranzport_probe(struct usb_interface *intf, | 789 | static int usb_tranzport_probe(struct usb_interface *intf, |
790 | const struct usb_device_id *id) { | 790 | const struct usb_device_id *id) { |
791 | struct usb_device *udev = interface_to_usbdev(intf); | 791 | struct usb_device *udev = interface_to_usbdev(intf); |
792 | struct usb_tranzport *dev = NULL; | 792 | struct usb_tranzport *dev = NULL; |
793 | struct usb_host_interface *iface_desc; | 793 | struct usb_host_interface *iface_desc; |
794 | struct usb_endpoint_descriptor *endpoint; | 794 | struct usb_endpoint_descriptor *endpoint; |
795 | int i; | 795 | int i; |
796 | int true_size; | 796 | int true_size; |
797 | int retval = -ENOMEM; | 797 | int retval = -ENOMEM; |
798 | 798 | ||
799 | /* allocate memory for our device state and initialize it */ | 799 | /* allocate memory for our device state and initialize it */ |
800 | 800 | ||
801 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | 801 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); |
802 | if (dev == NULL) { | 802 | if (dev == NULL) { |
803 | dev_err(&intf->dev, "Out of memory\n"); | 803 | dev_err(&intf->dev, "Out of memory\n"); |
804 | goto exit; | 804 | goto exit; |
805 | } | 805 | } |
806 | mutex_init(&dev->mtx); | 806 | mutex_init(&dev->mtx); |
807 | dev->intf = intf; | 807 | dev->intf = intf; |
808 | init_waitqueue_head(&dev->read_wait); | 808 | init_waitqueue_head(&dev->read_wait); |
809 | init_waitqueue_head(&dev->write_wait); | 809 | init_waitqueue_head(&dev->write_wait); |
810 | 810 | ||
811 | iface_desc = intf->cur_altsetting; | 811 | iface_desc = intf->cur_altsetting; |
812 | 812 | ||
813 | /* set up the endpoint information */ | 813 | /* set up the endpoint information */ |
814 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | 814 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { |
815 | endpoint = &iface_desc->endpoint[i].desc; | 815 | endpoint = &iface_desc->endpoint[i].desc; |
816 | 816 | ||
817 | if (usb_endpoint_is_int_in(endpoint)) | 817 | if (usb_endpoint_is_int_in(endpoint)) |
818 | dev->interrupt_in_endpoint = endpoint; | 818 | dev->interrupt_in_endpoint = endpoint; |
819 | 819 | ||
820 | if (usb_endpoint_is_int_out(endpoint)) | 820 | if (usb_endpoint_is_int_out(endpoint)) |
821 | dev->interrupt_out_endpoint = endpoint; | 821 | dev->interrupt_out_endpoint = endpoint; |
822 | } | 822 | } |
823 | if (dev->interrupt_in_endpoint == NULL) { | 823 | if (dev->interrupt_in_endpoint == NULL) { |
824 | dev_err(&intf->dev, "Interrupt in endpoint not found\n"); | 824 | dev_err(&intf->dev, "Interrupt in endpoint not found\n"); |
825 | goto error; | 825 | goto error; |
826 | } | 826 | } |
827 | if (dev->interrupt_out_endpoint == NULL) | 827 | if (dev->interrupt_out_endpoint == NULL) |
828 | dev_warn(&intf->dev, | 828 | dev_warn(&intf->dev, |
829 | "Interrupt out endpoint not found" | 829 | "Interrupt out endpoint not found" |
830 | "(using control endpoint instead)\n"); | 830 | "(using control endpoint instead)\n"); |
831 | 831 | ||
832 | dev->interrupt_in_endpoint_size = | 832 | dev->interrupt_in_endpoint_size = |
833 | le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); | 833 | le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize); |
834 | 834 | ||
835 | if (dev->interrupt_in_endpoint_size != 8) | 835 | if (dev->interrupt_in_endpoint_size != 8) |
836 | dev_warn(&intf->dev, "Interrupt in endpoint size is not 8!\n"); | 836 | dev_warn(&intf->dev, "Interrupt in endpoint size is not 8!\n"); |
837 | 837 | ||
838 | if (ring_buffer_size == 0) | 838 | if (ring_buffer_size == 0) |
839 | ring_buffer_size = RING_BUFFER_SIZE; | 839 | ring_buffer_size = RING_BUFFER_SIZE; |
840 | true_size = min(ring_buffer_size, RING_BUFFER_SIZE); | 840 | true_size = min(ring_buffer_size, RING_BUFFER_SIZE); |
841 | 841 | ||
842 | /* FIXME - there are more usb_alloc routines for dma correctness. | 842 | /* FIXME - there are more usb_alloc routines for dma correctness. |
843 | Needed? */ | 843 | Needed? */ |
844 | 844 | ||
845 | dev->ring_buffer = | 845 | dev->ring_buffer = |
846 | kmalloc((true_size * sizeof(struct tranzport_cmd)) + 8, GFP_KERNEL); | 846 | kmalloc((true_size * sizeof(struct tranzport_cmd)) + 8, GFP_KERNEL); |
847 | 847 | ||
848 | if (!dev->ring_buffer) { | 848 | if (!dev->ring_buffer) { |
849 | dev_err(&intf->dev, | 849 | dev_err(&intf->dev, |
850 | "Couldn't allocate ring_buffer size %d\n", true_size); | 850 | "Couldn't allocate ring_buffer size %d\n", true_size); |
851 | goto error; | 851 | goto error; |
852 | } | 852 | } |
853 | dev->interrupt_in_buffer = | 853 | dev->interrupt_in_buffer = |
854 | kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); | 854 | kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); |
855 | if (!dev->interrupt_in_buffer) { | 855 | if (!dev->interrupt_in_buffer) { |
856 | dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n"); | 856 | dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n"); |
857 | goto error; | 857 | goto error; |
858 | } | 858 | } |
859 | dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); | 859 | dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); |
860 | if (!dev->interrupt_in_urb) { | 860 | if (!dev->interrupt_in_urb) { |
861 | dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); | 861 | dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n"); |
862 | goto error; | 862 | goto error; |
863 | } | 863 | } |
864 | dev->interrupt_out_endpoint_size = | 864 | dev->interrupt_out_endpoint_size = |
865 | dev->interrupt_out_endpoint ? | 865 | dev->interrupt_out_endpoint ? |
866 | le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) : | 866 | le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) : |
867 | udev->descriptor.bMaxPacketSize0; | 867 | udev->descriptor.bMaxPacketSize0; |
868 | 868 | ||
869 | if (dev->interrupt_out_endpoint_size != 8) | 869 | if (dev->interrupt_out_endpoint_size != 8) |
870 | dev_warn(&intf->dev, | 870 | dev_warn(&intf->dev, |
871 | "Interrupt out endpoint size is not 8!)\n"); | 871 | "Interrupt out endpoint size is not 8!)\n"); |
872 | 872 | ||
873 | dev->interrupt_out_buffer = | 873 | dev->interrupt_out_buffer = |
874 | kmalloc(write_buffer_size * dev->interrupt_out_endpoint_size, | 874 | kmalloc(write_buffer_size * dev->interrupt_out_endpoint_size, |
875 | GFP_KERNEL); | 875 | GFP_KERNEL); |
876 | if (!dev->interrupt_out_buffer) { | 876 | if (!dev->interrupt_out_buffer) { |
877 | dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n"); | 877 | dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n"); |
878 | goto error; | 878 | goto error; |
879 | } | 879 | } |
880 | dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); | 880 | dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); |
881 | if (!dev->interrupt_out_urb) { | 881 | if (!dev->interrupt_out_urb) { |
882 | dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); | 882 | dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n"); |
883 | goto error; | 883 | goto error; |
884 | } | 884 | } |
885 | dev->interrupt_in_interval = | 885 | dev->interrupt_in_interval = |
886 | min_interrupt_in_interval > | 886 | min_interrupt_in_interval > |
887 | dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval | 887 | dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval |
888 | : dev->interrupt_in_endpoint->bInterval; | 888 | : dev->interrupt_in_endpoint->bInterval; |
889 | 889 | ||
890 | if (dev->interrupt_out_endpoint) { | 890 | if (dev->interrupt_out_endpoint) { |
891 | dev->interrupt_out_interval = | 891 | dev->interrupt_out_interval = |
892 | min_interrupt_out_interval > | 892 | min_interrupt_out_interval > |
893 | dev->interrupt_out_endpoint->bInterval ? | 893 | dev->interrupt_out_endpoint->bInterval ? |
894 | min_interrupt_out_interval : | 894 | min_interrupt_out_interval : |
895 | dev->interrupt_out_endpoint->bInterval; | 895 | dev->interrupt_out_endpoint->bInterval; |
896 | } | 896 | } |
897 | 897 | ||
898 | /* we can register the device now, as it is ready */ | 898 | /* we can register the device now, as it is ready */ |
899 | usb_set_intfdata(intf, dev); | 899 | usb_set_intfdata(intf, dev); |
900 | 900 | ||
901 | retval = usb_register_dev(intf, &usb_tranzport_class); | 901 | retval = usb_register_dev(intf, &usb_tranzport_class); |
902 | if (retval) { | 902 | if (retval) { |
903 | /* something prevented us from registering this driver */ | 903 | /* something prevented us from registering this driver */ |
904 | dev_err(&intf->dev, | 904 | dev_err(&intf->dev, |
905 | "Not able to get a minor for this device.\n"); | 905 | "Not able to get a minor for this device.\n"); |
906 | usb_set_intfdata(intf, NULL); | 906 | usb_set_intfdata(intf, NULL); |
907 | goto error; | 907 | goto error; |
908 | } | 908 | } |
909 | 909 | ||
910 | retval = device_create_file(&intf->dev, &dev_attr_compress_wheel); | 910 | retval = device_create_file(&intf->dev, &dev_attr_compress_wheel); |
911 | if (retval) | 911 | if (retval) |
912 | goto error; | 912 | goto error; |
913 | retval = device_create_file(&intf->dev, &dev_attr_enable); | 913 | retval = device_create_file(&intf->dev, &dev_attr_enable); |
914 | if (retval) | 914 | if (retval) |
915 | goto error; | 915 | goto error; |
916 | retval = device_create_file(&intf->dev, &dev_attr_offline); | 916 | retval = device_create_file(&intf->dev, &dev_attr_offline); |
917 | if (retval) | 917 | if (retval) |
918 | goto error; | 918 | goto error; |
919 | 919 | ||
920 | /* let the user know what node this device is now attached to */ | 920 | /* let the user know what node this device is now attached to */ |
921 | dev_info(&intf->dev, | 921 | dev_info(&intf->dev, |
922 | "Tranzport Device #%d now attached to major %d minor %d\n", | 922 | "Tranzport Device #%d now attached to major %d minor %d\n", |
923 | (intf->minor - USB_TRANZPORT_MINOR_BASE), USB_MAJOR, | 923 | (intf->minor - USB_TRANZPORT_MINOR_BASE), USB_MAJOR, |
924 | intf->minor); | 924 | intf->minor); |
925 | 925 | ||
926 | exit: | 926 | exit: |
927 | return retval; | 927 | return retval; |
928 | 928 | ||
929 | error: | 929 | error: |
930 | usb_tranzport_delete(dev); | 930 | usb_tranzport_delete(dev); |
931 | return retval; | 931 | return retval; |
932 | } | 932 | } |
933 | 933 | ||
934 | /** | 934 | /** |
935 | * usb_tranzport_disconnect | 935 | * usb_tranzport_disconnect |
936 | * | 936 | * |
937 | * Called by the usb core when the device is removed from the system. | 937 | * Called by the usb core when the device is removed from the system. |
938 | */ | 938 | */ |
939 | static void usb_tranzport_disconnect(struct usb_interface *intf) | 939 | static void usb_tranzport_disconnect(struct usb_interface *intf) |
940 | { | 940 | { |
941 | struct usb_tranzport *dev; | 941 | struct usb_tranzport *dev; |
942 | int minor; | 942 | int minor; |
943 | mutex_lock(&disconnect_mutex); | 943 | mutex_lock(&disconnect_mutex); |
944 | dev = usb_get_intfdata(intf); | 944 | dev = usb_get_intfdata(intf); |
945 | usb_set_intfdata(intf, NULL); | 945 | usb_set_intfdata(intf, NULL); |
946 | mutex_lock(&dev->mtx); | 946 | mutex_lock(&dev->mtx); |
947 | minor = intf->minor; | 947 | minor = intf->minor; |
948 | /* give back our minor */ | 948 | /* give back our minor */ |
949 | usb_deregister_dev(intf, &usb_tranzport_class); | 949 | usb_deregister_dev(intf, &usb_tranzport_class); |
950 | 950 | ||
951 | /* if the device is not opened, then we clean up right now */ | 951 | /* if the device is not opened, then we clean up right now */ |
952 | if (!dev->open_count) { | 952 | if (!dev->open_count) { |
953 | mutex_unlock(&dev->mtx); | 953 | mutex_unlock(&dev->mtx); |
954 | usb_tranzport_delete(dev); | 954 | usb_tranzport_delete(dev); |
955 | } else { | 955 | } else { |
956 | dev->intf = NULL; | 956 | dev->intf = NULL; |
957 | mutex_unlock(&dev->mtx); | 957 | mutex_unlock(&dev->mtx); |
958 | } | 958 | } |
959 | 959 | ||
960 | mutex_unlock(&disconnect_mutex); | 960 | mutex_unlock(&disconnect_mutex); |
961 | 961 | ||
962 | dev_info(&intf->dev, "Tranzport Surface #%d now disconnected\n", | 962 | dev_info(&intf->dev, "Tranzport Surface #%d now disconnected\n", |
963 | (minor - USB_TRANZPORT_MINOR_BASE)); | 963 | (minor - USB_TRANZPORT_MINOR_BASE)); |
964 | } | 964 | } |
965 | 965 | ||
966 | /* usb specific object needed to register this driver with the usb subsystem */ | 966 | /* usb specific object needed to register this driver with the usb subsystem */ |
967 | static struct usb_driver usb_tranzport_driver = { | 967 | static struct usb_driver usb_tranzport_driver = { |
968 | .name = "tranzport", | 968 | .name = "tranzport", |
969 | .probe = usb_tranzport_probe, | 969 | .probe = usb_tranzport_probe, |
970 | .disconnect = usb_tranzport_disconnect, | 970 | .disconnect = usb_tranzport_disconnect, |
971 | .id_table = usb_tranzport_table, | 971 | .id_table = usb_tranzport_table, |
972 | }; | 972 | }; |
973 | 973 | ||
974 | module_usb_driver(usb_tranzport_driver); | 974 | module_usb_driver(usb_tranzport_driver); |
975 | 975 |