blob: 2df22176515bc82f40c06efb3273f21c16ec4329 [file] [log] [blame]
Aleksey Babahin43d186f2012-03-08 13:18:43 -08001/*
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -08002 Some of this code is credited to Linux USB open source files that are
3 distributed with Linux.
Aleksey Babahin43d186f2012-03-08 13:18:43 -08004
5 Copyright: 2007 Metrologic Instruments. All rights reserved.
6 Copyright: 2011 Azimut Ltd. <http://azimutrzn.ru/>
Aleksey Babahin43d186f2012-03-08 13:18:43 -08007*/
8
9#include <linux/kernel.h>
10#include <linux/init.h>
11#include <linux/tty.h>
12#include <linux/module.h>
13#include <linux/usb.h>
14#include <linux/errno.h>
15#include <linux/slab.h>
16#include <linux/tty_driver.h>
17#include <linux/tty_flip.h>
18#include <linux/moduleparam.h>
19#include <linux/spinlock.h>
Aleksey Babahin43d186f2012-03-08 13:18:43 -080020#include <linux/errno.h>
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -080021#include <linux/uaccess.h>
Aleksey Babahin43d186f2012-03-08 13:18:43 -080022#include <linux/usb/serial.h>
23
24/* Version Information */
25#define DRIVER_VERSION "v1.2.0.0"
26#define DRIVER_DESC "Metrologic Instruments Inc. - USB-POS driver"
27
Greg Kroah-Hartman159d4d82012-03-08 13:42:41 -080028/* Product information. */
29#define FOCUS_VENDOR_ID 0x0C2E
Aleksey Babahin810ec782012-03-20 00:46:31 +040030#define FOCUS_PRODUCT_ID_BI 0x0720
31#define FOCUS_PRODUCT_ID_UNI 0x0700
Greg Kroah-Hartman159d4d82012-03-08 13:42:41 -080032
33#define METROUSB_SET_REQUEST_TYPE 0x40
34#define METROUSB_SET_MODEM_CTRL_REQUEST 10
35#define METROUSB_SET_BREAK_REQUEST 0x40
36#define METROUSB_MCR_NONE 0x08 /* Deactivate DTR and RTS. */
37#define METROUSB_MCR_RTS 0x0a /* Activate RTS. */
38#define METROUSB_MCR_DTR 0x09 /* Activate DTR. */
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -080039#define WDR_TIMEOUT 5000 /* default urb timeout. */
Greg Kroah-Hartman159d4d82012-03-08 13:42:41 -080040
41/* Private data structure. */
42struct metrousb_private {
43 spinlock_t lock;
44 int throttled;
45 unsigned long control_state;
46};
47
Aleksey Babahin43d186f2012-03-08 13:18:43 -080048/* Device table list. */
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -080049static struct usb_device_id id_table[] = {
Aleksey Babahin810ec782012-03-20 00:46:31 +040050 { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) },
Aleksey Babahin43d186f2012-03-08 13:18:43 -080051 { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },
Aleksey Babahin43d186f2012-03-08 13:18:43 -080052 { }, /* Terminating entry. */
53};
54MODULE_DEVICE_TABLE(usb, id_table);
55
56/* Input parameter constants. */
Greg Kroah-Hartmanfdac0f62012-03-08 13:37:32 -080057static bool debug;
Aleksey Babahin43d186f2012-03-08 13:18:43 -080058
Aleksey Babahin70457782012-03-20 00:46:33 +040059/* UNI-Directional mode commands for device configure */
60#define UNI_CMD_OPEN 0x80
61#define UNI_CMD_CLOSE 0xFF
62
63inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port)
64{
65 __u16 product_id = le16_to_cpu(
66 port->serial->dev->descriptor.idProduct);
67
68 return product_id == FOCUS_PRODUCT_ID_UNI;
69}
70
71static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port)
72{
73 int ret;
74 int actual_len;
75 u8 *buffer_cmd = NULL;
76
77 if (!metrousb_is_unidirectional_mode(port))
78 return 0;
79
80 buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL);
81 if (!buffer_cmd)
82 return -ENOMEM;
83
84 *buffer_cmd = cmd;
85
86 ret = usb_interrupt_msg(port->serial->dev,
87 usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
88 buffer_cmd, sizeof(cmd),
89 &actual_len, USB_CTRL_SET_TIMEOUT);
90
91 kfree(buffer_cmd);
92
93 if (ret < 0)
94 return ret;
95 else if (actual_len != sizeof(cmd))
96 return -EIO;
97 return 0;
98}
99
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800100static void metrousb_read_int_callback(struct urb *urb)
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800101{
Greg Kroah-Hartman8111e4e2012-03-08 14:00:11 -0800102 struct usb_serial_port *port = urb->context;
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800103 struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
104 struct tty_struct *tty;
105 unsigned char *data = urb->transfer_buffer;
106 int throttled = 0;
107 int result = 0;
108 unsigned long flags = 0;
109
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800110 dev_dbg(&port->dev, "%s\n", __func__);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800111
112 switch (urb->status) {
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800113 case 0:
114 /* Success status, read from the port. */
115 break;
116 case -ECONNRESET:
117 case -ENOENT:
118 case -ESHUTDOWN:
119 /* urb has been terminated. */
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800120 dev_dbg(&port->dev,
121 "%s - urb shutting down, error code=%d\n",
122 __func__, result);
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800123 return;
124 default:
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800125 dev_dbg(&port->dev,
126 "%s - non-zero urb received, error code=%d\n",
127 __func__, result);
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800128 goto exit;
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800129 }
130
131
132 /* Set the data read from the usb port into the serial port buffer. */
133 tty = tty_port_tty_get(&port->port);
134 if (!tty) {
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800135 dev_dbg(&port->dev, "%s - bad tty pointer - exiting\n",
136 __func__);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800137 return;
138 }
139
140 if (tty && urb->actual_length) {
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800141 /* Loop through the data copying each byte to the tty layer. */
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800142 tty_insert_flip_string(tty, data, urb->actual_length);
143
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800144 /* Force the data to the tty layer. */
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800145 tty_flip_buffer_push(tty);
146 }
147 tty_kref_put(tty);
148
149 /* Set any port variables. */
150 spin_lock_irqsave(&metro_priv->lock, flags);
151 throttled = metro_priv->throttled;
152 spin_unlock_irqrestore(&metro_priv->lock, flags);
153
154 /* Continue trying to read if set. */
155 if (!throttled) {
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800156 usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
157 usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress),
158 port->interrupt_in_urb->transfer_buffer,
159 port->interrupt_in_urb->transfer_buffer_length,
160 metrousb_read_int_callback, port, 1);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800161
162 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
163
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800164 if (result)
165 dev_dbg(&port->dev,
166 "%s - failed submitting interrupt in urb, error code=%d\n",
167 __func__, result);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800168 }
169 return;
170
171exit:
172 /* Try to resubmit the urb. */
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800173 result = usb_submit_urb(urb, GFP_ATOMIC);
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800174 if (result)
175 dev_dbg(&port->dev,
176 "%s - failed submitting interrupt in urb, error code=%d\n",
177 __func__, result);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800178}
179
Aleksey Babahin28a4b6a2012-03-20 00:46:32 +0400180static void metrousb_write_int_callback(struct urb *urb)
181{
182 struct usb_serial_port *port = urb->context;
183
184 dev_warn(&port->dev, "%s not implemented yet.\n",
185 __func__);
186}
187
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800188static void metrousb_cleanup(struct usb_serial_port *port)
189{
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800190 dev_dbg(&port->dev, "%s\n", __func__);
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800191
192 if (port->serial->dev) {
193 /* Shutdown any interrupt in urbs. */
194 if (port->interrupt_in_urb) {
195 usb_unlink_urb(port->interrupt_in_urb);
196 usb_kill_urb(port->interrupt_in_urb);
197 }
Aleksey Babahin70457782012-03-20 00:46:33 +0400198
199 /* Send deactivate cmd to device */
200 metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800201 }
202}
203
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800204static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
205{
206 struct usb_serial *serial = port->serial;
207 struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
208 unsigned long flags = 0;
209 int result = 0;
210
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800211 dev_dbg(&port->dev, "%s\n", __func__);
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800212
213 /* Make sure the urb is initialized. */
214 if (!port->interrupt_in_urb) {
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800215 dev_dbg(&port->dev, "%s - interrupt urb not initialized\n",
216 __func__);
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800217 return -ENODEV;
218 }
219
220 /* Set the private data information for the port. */
221 spin_lock_irqsave(&metro_priv->lock, flags);
222 metro_priv->control_state = 0;
223 metro_priv->throttled = 0;
224 spin_unlock_irqrestore(&metro_priv->lock, flags);
225
226 /*
227 * Force low_latency on so that our tty_push actually forces the data
228 * through, otherwise it is scheduled, and with high data rates (like
229 * with OHCI) data can get lost.
230 */
231 if (tty)
232 tty->low_latency = 1;
233
234 /* Clear the urb pipe. */
235 usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe);
236
237 /* Start reading from the device */
238 usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
239 usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
240 port->interrupt_in_urb->transfer_buffer,
241 port->interrupt_in_urb->transfer_buffer_length,
242 metrousb_read_int_callback, port, 1);
243 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
244
245 if (result) {
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800246 dev_dbg(&port->dev,
247 "%s - failed submitting interrupt in urb, error code=%d\n",
248 __func__, result);
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800249 goto exit;
250 }
251
Aleksey Babahin70457782012-03-20 00:46:33 +0400252 /* Send activate cmd to device */
253 result = metrousb_send_unidirectional_cmd(UNI_CMD_OPEN, port);
254 if (result) {
255 dev_err(&port->dev,
256 "%s - failed to configure device for port number=%d, error code=%d\n",
257 __func__, port->number, result);
258 goto exit;
259 }
260
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800261 dev_dbg(&port->dev, "%s - port open\n", __func__);
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800262exit:
263 return result;
264}
265
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800266static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int control_state)
267{
268 int retval = 0;
269 unsigned char mcr = METROUSB_MCR_NONE;
270
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800271 dev_dbg(&serial->dev->dev, "%s - control state = %d\n",
272 __func__, control_state);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800273
274 /* Set the modem control value. */
275 if (control_state & TIOCM_DTR)
276 mcr |= METROUSB_MCR_DTR;
277 if (control_state & TIOCM_RTS)
278 mcr |= METROUSB_MCR_RTS;
279
280 /* Send the command to the usb port. */
281 retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
282 METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST,
283 control_state, 0, NULL, 0, WDR_TIMEOUT);
284 if (retval < 0)
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800285 dev_dbg(&serial->dev->dev,
286 "%s - set modem ctrl=0x%x failed, error code=%d\n",
287 __func__, mcr, retval);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800288
289 return retval;
290}
291
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800292static void metrousb_shutdown(struct usb_serial *serial)
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800293{
294 int i = 0;
295
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800296 dev_dbg(&serial->dev->dev, "%s\n", __func__);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800297
298 /* Stop reading and writing on all ports. */
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800299 for (i = 0; i < serial->num_ports; ++i) {
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800300 /* Close any open urbs. */
301 metrousb_cleanup(serial->port[i]);
302
303 /* Free memory. */
304 kfree(usb_get_serial_port_data(serial->port[i]));
305 usb_set_serial_port_data(serial->port[i], NULL);
306
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800307 dev_dbg(&serial->dev->dev, "%s - freed port number=%d\n",
308 __func__, serial->port[i]->number);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800309 }
310}
311
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800312static int metrousb_startup(struct usb_serial *serial)
313{
314 struct metrousb_private *metro_priv;
315 struct usb_serial_port *port;
316 int i = 0;
317
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800318 dev_dbg(&serial->dev->dev, "%s\n", __func__);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800319
320 /* Loop through the serial ports setting up the private structures.
321 * Currently we only use one port. */
322 for (i = 0; i < serial->num_ports; ++i) {
323 port = serial->port[i];
324
325 /* Declare memory. */
Greg Kroah-Hartman8111e4e2012-03-08 14:00:11 -0800326 metro_priv = kzalloc(sizeof(struct metrousb_private), GFP_KERNEL);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800327 if (!metro_priv)
328 return -ENOMEM;
329
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800330 /* Initialize memory. */
331 spin_lock_init(&metro_priv->lock);
332 usb_set_serial_port_data(port, metro_priv);
333
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800334 dev_dbg(&serial->dev->dev, "%s - port number=%d\n ",
335 __func__, port->number);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800336 }
337
338 return 0;
339}
340
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800341static void metrousb_throttle(struct tty_struct *tty)
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800342{
343 struct usb_serial_port *port = tty->driver_data;
344 struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
345 unsigned long flags = 0;
346
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800347 dev_dbg(tty->dev, "%s\n", __func__);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800348
349 /* Set the private information for the port to stop reading data. */
350 spin_lock_irqsave(&metro_priv->lock, flags);
351 metro_priv->throttled = 1;
352 spin_unlock_irqrestore(&metro_priv->lock, flags);
353}
354
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800355static int metrousb_tiocmget(struct tty_struct *tty)
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800356{
357 unsigned long control_state = 0;
358 struct usb_serial_port *port = tty->driver_data;
359 struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
360 unsigned long flags = 0;
361
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800362 dev_dbg(tty->dev, "%s\n", __func__);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800363
364 spin_lock_irqsave(&metro_priv->lock, flags);
365 control_state = metro_priv->control_state;
366 spin_unlock_irqrestore(&metro_priv->lock, flags);
367
368 return control_state;
369}
370
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800371static int metrousb_tiocmset(struct tty_struct *tty,
372 unsigned int set, unsigned int clear)
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800373{
374 struct usb_serial_port *port = tty->driver_data;
375 struct usb_serial *serial = port->serial;
376 struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
377 unsigned long flags = 0;
378 unsigned long control_state = 0;
379
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800380 dev_dbg(tty->dev, "%s - set=%d, clear=%d\n", __func__, set, clear);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800381
382 spin_lock_irqsave(&metro_priv->lock, flags);
383 control_state = metro_priv->control_state;
384
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800385 /* Set the RTS and DTR values. */
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800386 if (set & TIOCM_RTS)
387 control_state |= TIOCM_RTS;
388 if (set & TIOCM_DTR)
389 control_state |= TIOCM_DTR;
390 if (clear & TIOCM_RTS)
391 control_state &= ~TIOCM_RTS;
392 if (clear & TIOCM_DTR)
393 control_state &= ~TIOCM_DTR;
394
395 metro_priv->control_state = control_state;
396 spin_unlock_irqrestore(&metro_priv->lock, flags);
397 return metrousb_set_modem_ctrl(serial, control_state);
398}
399
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800400static void metrousb_unthrottle(struct tty_struct *tty)
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800401{
402 struct usb_serial_port *port = tty->driver_data;
403 struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
404 unsigned long flags = 0;
405 int result = 0;
406
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800407 dev_dbg(tty->dev, "%s\n", __func__);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800408
409 /* Set the private information for the port to resume reading data. */
410 spin_lock_irqsave(&metro_priv->lock, flags);
411 metro_priv->throttled = 0;
412 spin_unlock_irqrestore(&metro_priv->lock, flags);
413
414 /* Submit the urb to read from the port. */
415 port->interrupt_in_urb->dev = port->serial->dev;
416 result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
Greg Kroah-Hartman5db51b52012-03-08 14:16:12 -0800417 if (result)
418 dev_dbg(tty->dev,
419 "failed submitting interrupt in urb error code=%d\n",
420 result);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800421}
422
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800423static struct usb_driver metrousb_driver = {
424 .name = "metro-usb",
425 .probe = usb_serial_probe,
426 .disconnect = usb_serial_disconnect,
427 .id_table = id_table
428};
429
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800430static struct usb_serial_driver metrousb_device = {
431 .driver = {
432 .owner = THIS_MODULE,
433 .name = "metro-usb",
434 },
435 .description = "Metrologic USB to serial converter.",
436 .id_table = id_table,
437 .num_ports = 1,
438 .open = metrousb_open,
439 .close = metrousb_cleanup,
440 .read_int_callback = metrousb_read_int_callback,
Aleksey Babahin28a4b6a2012-03-20 00:46:32 +0400441 .write_int_callback = metrousb_write_int_callback,
Greg Kroah-Hartman9fbd1642012-03-08 13:55:41 -0800442 .attach = metrousb_startup,
443 .release = metrousb_shutdown,
444 .throttle = metrousb_throttle,
445 .unthrottle = metrousb_unthrottle,
446 .tiocmget = metrousb_tiocmget,
447 .tiocmset = metrousb_tiocmset,
448};
449
450static struct usb_serial_driver * const serial_drivers[] = {
451 &metrousb_device,
452 NULL,
453};
454
Greg Kroah-Hartman1935e352012-03-08 13:39:53 -0800455module_usb_serial_driver(metrousb_driver, serial_drivers);
456
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800457MODULE_LICENSE("GPL");
Greg Kroah-Hartmand4cbd6e2012-03-08 13:50:54 -0800458MODULE_AUTHOR("Philip Nicastro");
459MODULE_AUTHOR("Aleksey Babahin <tamerlan311@gmail.com>");
460MODULE_DESCRIPTION(DRIVER_DESC);
Aleksey Babahin43d186f2012-03-08 13:18:43 -0800461
462/* Module input parameters */
463module_param(debug, bool, S_IRUGO | S_IWUSR);
464MODULE_PARM_DESC(debug, "Print debug info (bool 1=on, 0=off)");