blob: 03fe472fee3215456db80a38971b88880371ca13 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Prolific PL2303 USB to serial adaptor driver
3 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07004 * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Copyright (C) 2003 IBM Corp.
6 *
7 * Original driver for 2.2.x by anonymous
8 *
Greg Kroah-Hartman4d0dce32007-06-12 11:43:37 -07009 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version
11 * 2 as published by the Free Software Foundation.
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 *
Alan Cox3a0f43e2008-07-22 11:14:49 +010013 * See Documentation/usb/usb-serial.txt for more information on using this
14 * driver
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070016 */
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/kernel.h>
19#include <linux/errno.h>
20#include <linux/init.h>
21#include <linux/slab.h>
22#include <linux/tty.h>
23#include <linux/tty_driver.h>
24#include <linux/tty_flip.h>
25#include <linux/serial.h>
26#include <linux/module.h>
27#include <linux/moduleparam.h>
28#include <linux/spinlock.h>
Alan Cox3a0f43e2008-07-22 11:14:49 +010029#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/usb.h>
Greg Kroah-Hartmana9698882006-07-11 21:22:58 -070031#include <linux/usb/serial.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "pl2303.h"
33
34/*
35 * Version Information
36 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
38
39static int debug;
40
41#define PL2303_CLOSING_WAIT (30*HZ)
42
43#define PL2303_BUF_SIZE 1024
44#define PL2303_TMP_BUF_SIZE 1024
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046struct pl2303_buf {
47 unsigned int buf_size;
48 char *buf_buf;
49 char *buf_get;
50 char *buf_put;
51};
52
Németh Márton7d40d7e2010-01-10 15:34:24 +010053static const struct usb_device_id id_table[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
55 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
Peter Moulder3d861492006-06-19 22:47:49 +100056 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
58 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
Max Arnoldb483b6a2008-03-20 16:43:56 +070059 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ALDIGA) },
Steve Murphy4be2fa12008-05-23 23:39:05 +053060 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MMX) },
Greg Kroah-Hartman727df352008-07-02 15:25:41 -050061 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GPRS) },
Simone Contini18344a12010-04-12 23:25:10 +020062 { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_HCR331) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
Masakazu Mokuno8a28dea2007-10-23 13:51:57 +090064 { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
66 { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
67 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
68 { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
69 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID) },
Wang Jun58381712006-04-19 16:32:07 +080070 { USB_DEVICE(ITEGNO_VENDOR_ID, ITEGNO_PRODUCT_ID_2080) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 { USB_DEVICE(MA620_VENDOR_ID, MA620_PRODUCT_ID) },
72 { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID) },
73 { USB_DEVICE(TRIPP_VENDOR_ID, TRIPP_PRODUCT_ID) },
74 { USB_DEVICE(RADIOSHACK_VENDOR_ID, RADIOSHACK_PRODUCT_ID) },
75 { USB_DEVICE(DCU10_VENDOR_ID, DCU10_PRODUCT_ID) },
76 { USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },
77 { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },
78 { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080079 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) },
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) },
Luiz Fernando Capitulinoa8310f32005-11-17 09:47:32 -080081 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) },
Andreas Loible7beb662007-08-24 01:51:11 +020082 { USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },
Alan Cox912299f2009-04-06 17:35:12 +010083 { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */
Peter Favrholdtacbb36f2005-04-18 17:39:32 -070084 { USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010085 { USB_DEVICE(NOKIA_CA42_VENDOR_ID, NOKIA_CA42_PRODUCT_ID) },
86 { USB_DEVICE(CA_42_CA42_VENDOR_ID, CA_42_CA42_PRODUCT_ID) },
Denis MONTERRAT6cceb052006-01-19 14:52:38 +010087 { USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
Christian Lindnerc6c27722006-02-01 14:10:52 +010088 { USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
Dick Streefland491b04c2006-03-01 00:53:33 -080089 { USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
Matthew Meno3b928472006-06-21 15:25:53 -040090 { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
Kim Oldfieldb7aa94b2006-07-25 15:54:59 +100091 { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
Johannes Steingraeber8fd80132006-09-16 16:17:34 +020092 { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
YOSHIFUJI Hideaki2d94b982007-01-26 22:51:38 +090093 { USB_DEVICE(WS002IN_VENDOR_ID, WS002IN_PRODUCT_ID) },
Magnus Damm9e3285d2007-11-08 16:45:46 +090094 { USB_DEVICE(COREGA_VENDOR_ID, COREGA_PRODUCT_ID) },
Damien Stuartcc311ee2008-01-06 13:51:39 -050095 { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },
Matthew Arnold7c992002008-12-13 22:42:53 +110096 { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },
Mike Provencheraf4b8512008-12-16 14:30:14 -060097 { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) },
Gianpaolo Cugola8540d662009-06-05 22:57:52 +020098 { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },
Khanh-Dang Nguyen Thu Lam49276562009-07-28 19:41:17 +020099 { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) },
Pawel Ludwikow35904e62009-08-27 14:15:50 +0200100 { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) },
Manuel Jander9a61d722010-03-29 23:51:57 +0200101 { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 { } /* Terminating entry */
103};
104
Thiago Galesi372db8a2006-07-31 15:39:27 -0300105MODULE_DEVICE_TABLE(usb, id_table);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106
107static struct usb_driver pl2303_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 .name = "pl2303",
109 .probe = usb_serial_probe,
110 .disconnect = usb_serial_disconnect,
111 .id_table = id_table,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800112 .suspend = usb_serial_suspend,
113 .resume = usb_serial_resume,
Greg Kroah-Hartmanba9dc652005-11-16 13:41:28 -0800114 .no_dynamic_id = 1,
Sarah Sharpfcf9e552007-12-14 14:09:30 -0800115 .supports_autosuspend = 1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116};
117
118#define SET_LINE_REQUEST_TYPE 0x21
119#define SET_LINE_REQUEST 0x20
120
121#define SET_CONTROL_REQUEST_TYPE 0x21
122#define SET_CONTROL_REQUEST 0x22
123#define CONTROL_DTR 0x01
124#define CONTROL_RTS 0x02
125
126#define BREAK_REQUEST_TYPE 0x21
Alan Cox3a0f43e2008-07-22 11:14:49 +0100127#define BREAK_REQUEST 0x23
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128#define BREAK_ON 0xffff
129#define BREAK_OFF 0x0000
130
131#define GET_LINE_REQUEST_TYPE 0xa1
132#define GET_LINE_REQUEST 0x21
133
134#define VENDOR_WRITE_REQUEST_TYPE 0x40
135#define VENDOR_WRITE_REQUEST 0x01
136
137#define VENDOR_READ_REQUEST_TYPE 0xc0
138#define VENDOR_READ_REQUEST 0x01
139
140#define UART_STATE 0x08
141#define UART_STATE_TRANSIENT_MASK 0x74
142#define UART_DCD 0x01
143#define UART_DSR 0x02
144#define UART_BREAK_ERROR 0x04
145#define UART_RING 0x08
146#define UART_FRAME_ERROR 0x10
147#define UART_PARITY_ERROR 0x20
148#define UART_OVERRUN_ERROR 0x40
149#define UART_CTS 0x80
150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151
152enum pl2303_type {
153 type_0, /* don't know the difference between type 0 and */
154 type_1, /* type 1, until someone from prolific tells us... */
155 HX, /* HX version of the pl2303 chip */
156};
157
158struct pl2303_private {
159 spinlock_t lock;
160 struct pl2303_buf *buf;
161 int write_urb_in_use;
162 wait_queue_head_t delta_msr_wait;
163 u8 line_control;
164 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 enum pl2303_type type;
166};
167
Thiago Galesi572d3132006-07-29 10:46:37 -0300168/*
169 * pl2303_buf_alloc
170 *
171 * Allocate a circular buffer and all associated memory.
172 */
173static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
174{
175 struct pl2303_buf *pb;
176
177 if (size == 0)
178 return NULL;
179
Robert P. J. Day5cbded52006-12-13 00:35:56 -0800180 pb = kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
Thiago Galesi572d3132006-07-29 10:46:37 -0300181 if (pb == NULL)
182 return NULL;
183
184 pb->buf_buf = kmalloc(size, GFP_KERNEL);
185 if (pb->buf_buf == NULL) {
186 kfree(pb);
187 return NULL;
188 }
189
190 pb->buf_size = size;
191 pb->buf_get = pb->buf_put = pb->buf_buf;
192
193 return pb;
194}
195
196/*
197 * pl2303_buf_free
198 *
199 * Free the buffer and all associated memory.
200 */
201static void pl2303_buf_free(struct pl2303_buf *pb)
202{
203 if (pb) {
204 kfree(pb->buf_buf);
205 kfree(pb);
206 }
207}
208
209/*
210 * pl2303_buf_clear
211 *
212 * Clear out all data in the circular buffer.
213 */
214static void pl2303_buf_clear(struct pl2303_buf *pb)
215{
216 if (pb != NULL)
217 pb->buf_get = pb->buf_put;
218 /* equivalent to a get of all data available */
219}
220
221/*
222 * pl2303_buf_data_avail
223 *
224 * Return the number of bytes of data available in the circular
225 * buffer.
226 */
227static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
228{
229 if (pb == NULL)
230 return 0;
231
Alan Cox3a0f43e2008-07-22 11:14:49 +0100232 return (pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300233}
234
235/*
236 * pl2303_buf_space_avail
237 *
238 * Return the number of bytes of space available in the circular
239 * buffer.
240 */
241static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
242{
243 if (pb == NULL)
244 return 0;
245
Alan Cox3a0f43e2008-07-22 11:14:49 +0100246 return (pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size;
Thiago Galesi572d3132006-07-29 10:46:37 -0300247}
248
249/*
250 * pl2303_buf_put
251 *
252 * Copy data data from a user buffer and put it into the circular buffer.
253 * Restrict to the amount of space available.
254 *
255 * Return the number of bytes copied.
256 */
257static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
258 unsigned int count)
259{
260 unsigned int len;
261
262 if (pb == NULL)
263 return 0;
264
265 len = pl2303_buf_space_avail(pb);
266 if (count > len)
267 count = len;
268
269 if (count == 0)
270 return 0;
271
272 len = pb->buf_buf + pb->buf_size - pb->buf_put;
273 if (count > len) {
274 memcpy(pb->buf_put, buf, len);
275 memcpy(pb->buf_buf, buf+len, count - len);
276 pb->buf_put = pb->buf_buf + count - len;
277 } else {
278 memcpy(pb->buf_put, buf, count);
279 if (count < len)
280 pb->buf_put += count;
281 else /* count == len */
282 pb->buf_put = pb->buf_buf;
283 }
284
285 return count;
286}
287
288/*
289 * pl2303_buf_get
290 *
291 * Get data from the circular buffer and copy to the given buffer.
292 * Restrict to the amount of data available.
293 *
294 * Return the number of bytes copied.
295 */
296static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
297 unsigned int count)
298{
299 unsigned int len;
300
301 if (pb == NULL)
302 return 0;
303
304 len = pl2303_buf_data_avail(pb);
305 if (count > len)
306 count = len;
307
308 if (count == 0)
309 return 0;
310
311 len = pb->buf_buf + pb->buf_size - pb->buf_get;
312 if (count > len) {
313 memcpy(buf, pb->buf_get, len);
314 memcpy(buf+len, pb->buf_buf, count - len);
315 pb->buf_get = pb->buf_buf + count - len;
316 } else {
317 memcpy(buf, pb->buf_get, count);
318 if (count < len)
319 pb->buf_get += count;
320 else /* count == len */
321 pb->buf_get = pb->buf_buf;
322 }
323
324 return count;
325}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Sarah Sharpeb44da02007-12-14 14:08:00 -0800327static int pl2303_vendor_read(__u16 value, __u16 index,
328 struct usb_serial *serial, unsigned char *buf)
329{
330 int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
331 VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,
332 value, index, buf, 1, 100);
333 dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE,
334 VENDOR_READ_REQUEST, value, index, res, buf[0]);
335 return res;
336}
337
338static int pl2303_vendor_write(__u16 value, __u16 index,
339 struct usb_serial *serial)
340{
341 int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
342 VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,
343 value, index, NULL, 0, 100);
344 dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE,
345 VENDOR_WRITE_REQUEST, value, index, res);
346 return res;
347}
348
Thiago Galesi372db8a2006-07-31 15:39:27 -0300349static int pl2303_startup(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
351 struct pl2303_private *priv;
352 enum pl2303_type type = type_0;
Sarah Sharp3e152502007-12-14 14:08:35 -0800353 unsigned char *buf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 int i;
355
Sarah Sharp3e152502007-12-14 14:08:35 -0800356 buf = kmalloc(10, GFP_KERNEL);
357 if (buf == NULL)
358 return -ENOMEM;
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 if (serial->dev->descriptor.bDeviceClass == 0x02)
361 type = type_0;
362 else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40)
363 type = HX;
364 else if (serial->dev->descriptor.bDeviceClass == 0x00)
365 type = type_1;
366 else if (serial->dev->descriptor.bDeviceClass == 0xFF)
367 type = type_1;
368 dbg("device type: %d", type);
369
370 for (i = 0; i < serial->num_ports; ++i) {
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +0100371 priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 if (!priv)
373 goto cleanup;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 spin_lock_init(&priv->lock);
375 priv->buf = pl2303_buf_alloc(PL2303_BUF_SIZE);
376 if (priv->buf == NULL) {
377 kfree(priv);
378 goto cleanup;
379 }
380 init_waitqueue_head(&priv->delta_msr_wait);
381 priv->type = type;
382 usb_set_serial_port_data(serial->port[i], priv);
383 }
Sarah Sharp3e152502007-12-14 14:08:35 -0800384
385 pl2303_vendor_read(0x8484, 0, serial, buf);
386 pl2303_vendor_write(0x0404, 0, serial);
387 pl2303_vendor_read(0x8484, 0, serial, buf);
388 pl2303_vendor_read(0x8383, 0, serial, buf);
389 pl2303_vendor_read(0x8484, 0, serial, buf);
390 pl2303_vendor_write(0x0404, 1, serial);
391 pl2303_vendor_read(0x8484, 0, serial, buf);
392 pl2303_vendor_read(0x8383, 0, serial, buf);
393 pl2303_vendor_write(0, 1, serial);
394 pl2303_vendor_write(1, 0, serial);
395 if (type == HX)
396 pl2303_vendor_write(2, 0x44, serial);
397 else
398 pl2303_vendor_write(2, 0x24, serial);
399
400 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 return 0;
402
403cleanup:
Sarah Sharp3e152502007-12-14 14:08:35 -0800404 kfree(buf);
Alan Cox3a0f43e2008-07-22 11:14:49 +0100405 for (--i; i >= 0; --i) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 priv = usb_get_serial_port_data(serial->port[i]);
407 pl2303_buf_free(priv->buf);
408 kfree(priv);
409 usb_set_serial_port_data(serial->port[i], NULL);
410 }
411 return -ENOMEM;
412}
413
Thiago Galesi372db8a2006-07-31 15:39:27 -0300414static int set_control_lines(struct usb_device *dev, u8 value)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
416 int retval;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100417
Thiago Galesi372db8a2006-07-31 15:39:27 -0300418 retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
419 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
420 value, 0, NULL, 0, 100);
Harvey Harrison441b62c2008-03-03 16:08:34 -0800421 dbg("%s - value = %d, retval = %d", __func__, value, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 return retval;
423}
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425static void pl2303_send(struct usb_serial_port *port)
426{
427 int count, result;
428 struct pl2303_private *priv = usb_get_serial_port_data(port);
429 unsigned long flags;
430
Harvey Harrison441b62c2008-03-03 16:08:34 -0800431 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
433 spin_lock_irqsave(&priv->lock, flags);
434
435 if (priv->write_urb_in_use) {
436 spin_unlock_irqrestore(&priv->lock, flags);
437 return;
438 }
439
440 count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300441 port->bulk_out_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442
443 if (count == 0) {
444 spin_unlock_irqrestore(&priv->lock, flags);
445 return;
446 }
447
448 priv->write_urb_in_use = 1;
449
450 spin_unlock_irqrestore(&priv->lock, flags);
451
Harvey Harrison441b62c2008-03-03 16:08:34 -0800452 usb_serial_debug_data(debug, &port->dev, __func__, count,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300453 port->write_urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454
455 port->write_urb->transfer_buffer_length = count;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300456 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300458 dev_err(&port->dev, "%s - failed submitting write urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800459 " error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 priv->write_urb_in_use = 0;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100461 /* TODO: reschedule pl2303_send */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 }
463
Pete Zaitcevcf2c7482006-05-22 21:58:49 -0700464 usb_serial_port_softint(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465}
466
Alan Cox95da3102008-07-22 11:09:07 +0100467static int pl2303_write(struct tty_struct *tty, struct usb_serial_port *port,
468 const unsigned char *buf, int count)
Thiago Galesi572d3132006-07-29 10:46:37 -0300469{
470 struct pl2303_private *priv = usb_get_serial_port_data(port);
471 unsigned long flags;
472
Harvey Harrison441b62c2008-03-03 16:08:34 -0800473 dbg("%s - port %d, %d bytes", __func__, port->number, count);
Thiago Galesi572d3132006-07-29 10:46:37 -0300474
475 if (!count)
476 return count;
477
478 spin_lock_irqsave(&priv->lock, flags);
479 count = pl2303_buf_put(priv->buf, buf, count);
480 spin_unlock_irqrestore(&priv->lock, flags);
481
482 pl2303_send(port);
483
484 return count;
485}
486
Alan Cox95da3102008-07-22 11:09:07 +0100487static int pl2303_write_room(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488{
Alan Cox95da3102008-07-22 11:09:07 +0100489 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 struct pl2303_private *priv = usb_get_serial_port_data(port);
491 int room = 0;
492 unsigned long flags;
493
Harvey Harrison441b62c2008-03-03 16:08:34 -0800494 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496 spin_lock_irqsave(&priv->lock, flags);
497 room = pl2303_buf_space_avail(priv->buf);
498 spin_unlock_irqrestore(&priv->lock, flags);
499
Harvey Harrison441b62c2008-03-03 16:08:34 -0800500 dbg("%s - returns %d", __func__, room);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 return room;
502}
503
Alan Cox95da3102008-07-22 11:09:07 +0100504static int pl2303_chars_in_buffer(struct tty_struct *tty)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505{
Alan Cox95da3102008-07-22 11:09:07 +0100506 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 struct pl2303_private *priv = usb_get_serial_port_data(port);
508 int chars = 0;
509 unsigned long flags;
510
Harvey Harrison441b62c2008-03-03 16:08:34 -0800511 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 spin_lock_irqsave(&priv->lock, flags);
514 chars = pl2303_buf_data_avail(priv->buf);
515 spin_unlock_irqrestore(&priv->lock, flags);
516
Harvey Harrison441b62c2008-03-03 16:08:34 -0800517 dbg("%s - returns %d", __func__, chars);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 return chars;
519}
520
Alan Cox95da3102008-07-22 11:09:07 +0100521static void pl2303_set_termios(struct tty_struct *tty,
522 struct usb_serial_port *port, struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523{
524 struct usb_serial *serial = port->serial;
525 struct pl2303_private *priv = usb_get_serial_port_data(port);
526 unsigned long flags;
527 unsigned int cflag;
528 unsigned char *buf;
529 int baud;
530 int i;
531 u8 control;
Frank Schaefer25b82862009-08-18 20:15:07 +0200532 const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600,
533 4800, 7200, 9600, 14400, 19200, 28800, 38400,
534 57600, 115200, 230400, 460800, 614400,
535 921600, 1228800, 2457600, 3000000, 6000000 };
536 int baud_floor, baud_ceil;
537 int k;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
Harvey Harrison441b62c2008-03-03 16:08:34 -0800539 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540
Alan Coxbf5e5832008-01-08 14:55:51 +0000541 /* The PL2303 is reported to lose bytes if you change
542 serial settings even to the same values as before. Thus
543 we actually need to filter in this specific case */
544
Alan Cox95da3102008-07-22 11:09:07 +0100545 if (!tty_termios_hw_change(tty->termios, old_termios))
Alan Coxbf5e5832008-01-08 14:55:51 +0000546 return;
547
Alan Cox95da3102008-07-22 11:09:07 +0100548 cflag = tty->termios->c_cflag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549
Thiago Galesi372db8a2006-07-31 15:39:27 -0300550 buf = kzalloc(7, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 if (!buf) {
Harvey Harrison441b62c2008-03-03 16:08:34 -0800552 dev_err(&port->dev, "%s - out of memory.\n", __func__);
Alan Coxa5b6f602008-04-08 17:16:06 +0100553 /* Report back no change occurred */
Alan Cox95da3102008-07-22 11:09:07 +0100554 *tty->termios = *old_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 return;
556 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557
Thiago Galesi372db8a2006-07-31 15:39:27 -0300558 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
559 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
560 0, 0, buf, 7, 100);
561 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
562 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
564 if (cflag & CSIZE) {
565 switch (cflag & CSIZE) {
Alan Cox3a0f43e2008-07-22 11:14:49 +0100566 case CS5:
567 buf[6] = 5;
568 break;
569 case CS6:
570 buf[6] = 6;
571 break;
572 case CS7:
573 buf[6] = 7;
574 break;
575 default:
576 case CS8:
577 buf[6] = 8;
578 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 }
Harvey Harrison441b62c2008-03-03 16:08:34 -0800580 dbg("%s - data bits = %d", __func__, buf[6]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 }
582
Frank Schaefer25b82862009-08-18 20:15:07 +0200583 /* For reference buf[0]:buf[3] baud rate value */
584 /* NOTE: Only the values defined in baud_sup are supported !
585 * => if unsupported values are set, the PL2303 seems to use
586 * 9600 baud (at least my PL2303X always does)
587 */
Alan Cox95da3102008-07-22 11:09:07 +0100588 baud = tty_get_baud_rate(tty);
Frank Schaefer25b82862009-08-18 20:15:07 +0200589 dbg("%s - baud requested = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 if (baud) {
Frank Schaefer25b82862009-08-18 20:15:07 +0200591 /* Set baudrate to nearest supported value */
592 for (k=0; k<ARRAY_SIZE(baud_sup); k++) {
593 if (baud_sup[k] / baud) {
594 baud_ceil = baud_sup[k];
595 if (k==0) {
596 baud = baud_ceil;
597 } else {
598 baud_floor = baud_sup[k-1];
599 if ((baud_ceil % baud)
600 > (baud % baud_floor))
601 baud = baud_floor;
602 else
603 baud = baud_ceil;
604 }
605 break;
606 }
607 }
608 if (baud > 1228800) {
609 /* type_0, type_1 only support up to 1228800 baud */
610 if (priv->type != HX)
611 baud = 1228800;
612 else if (baud > 6000000)
613 baud = 6000000;
614 }
615 dbg("%s - baud set = %d", __func__, baud);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 buf[0] = baud & 0xff;
617 buf[1] = (baud >> 8) & 0xff;
618 buf[2] = (baud >> 16) & 0xff;
619 buf[3] = (baud >> 24) & 0xff;
620 }
621
622 /* For reference buf[4]=0 is 1 stop bits */
623 /* For reference buf[4]=1 is 1.5 stop bits */
624 /* For reference buf[4]=2 is 2 stop bits */
625 if (cflag & CSTOPB) {
Frank Schaefer29cf1b72009-08-18 20:34:24 +0200626 /* NOTE: Comply with "real" UARTs / RS232:
627 * use 1.5 instead of 2 stop bits with 5 data bits
628 */
629 if ((cflag & CSIZE) == CS5) {
630 buf[4] = 1;
631 dbg("%s - stop bits = 1.5", __func__);
632 } else {
633 buf[4] = 2;
634 dbg("%s - stop bits = 2", __func__);
635 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636 } else {
637 buf[4] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800638 dbg("%s - stop bits = 1", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 }
640
641 if (cflag & PARENB) {
642 /* For reference buf[5]=0 is none parity */
643 /* For reference buf[5]=1 is odd parity */
644 /* For reference buf[5]=2 is even parity */
645 /* For reference buf[5]=3 is mark parity */
646 /* For reference buf[5]=4 is space parity */
647 if (cflag & PARODD) {
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200648 if (cflag & CMSPAR) {
649 buf[5] = 3;
650 dbg("%s - parity = mark", __func__);
651 } else {
652 buf[5] = 1;
653 dbg("%s - parity = odd", __func__);
654 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 } else {
Frank Schaefer6dd81b42009-08-18 20:31:11 +0200656 if (cflag & CMSPAR) {
657 buf[5] = 4;
658 dbg("%s - parity = space", __func__);
659 } else {
660 buf[5] = 2;
661 dbg("%s - parity = even", __func__);
662 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 }
664 } else {
665 buf[5] = 0;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800666 dbg("%s - parity = none", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 }
668
Thiago Galesi372db8a2006-07-31 15:39:27 -0300669 i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
670 SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
671 0, 0, buf, 7, 100);
672 dbg("0x21:0x20:0:0 %d", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674 /* change control lines if we are switching to or from B0 */
675 spin_lock_irqsave(&priv->lock, flags);
676 control = priv->line_control;
677 if ((cflag & CBAUD) == B0)
678 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
679 else
680 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
681 if (control != priv->line_control) {
682 control = priv->line_control;
683 spin_unlock_irqrestore(&priv->lock, flags);
684 set_control_lines(serial->dev, control);
685 } else {
686 spin_unlock_irqrestore(&priv->lock, flags);
687 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300688
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
690
Thiago Galesi372db8a2006-07-31 15:39:27 -0300691 i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
692 GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
693 0, 0, buf, 7, 100);
694 dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
696
697 if (cflag & CRTSCTS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 if (priv->type == HX)
Sarah Sharpeb44da02007-12-14 14:08:00 -0800699 pl2303_vendor_write(0x0, 0x61, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 else
Sarah Sharpeb44da02007-12-14 14:08:00 -0800701 pl2303_vendor_write(0x0, 0x41, serial);
t.sefzick715f9522007-04-25 15:05:22 +0200702 } else {
Sarah Sharpeb44da02007-12-14 14:08:00 -0800703 pl2303_vendor_write(0x0, 0x0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 }
705
Frank Schaefer25b82862009-08-18 20:15:07 +0200706 /* Save resulting baud rate */
Alan Coxdf64c472007-10-15 20:54:47 +0100707 if (baud)
Alan Cox95da3102008-07-22 11:09:07 +0100708 tty_encode_baud_rate(tty, baud, baud);
Alan Coxdf64c472007-10-15 20:54:47 +0100709
Thiago Galesi372db8a2006-07-31 15:39:27 -0300710 kfree(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711}
712
Alan Cox335f8512009-06-11 12:26:29 +0100713static void pl2303_dtr_rts(struct usb_serial_port *port, int on)
Thiago Galesi572d3132006-07-29 10:46:37 -0300714{
715 struct pl2303_private *priv = usb_get_serial_port_data(port);
716 unsigned long flags;
Alan Cox335f8512009-06-11 12:26:29 +0100717 u8 control;
718
719 spin_lock_irqsave(&priv->lock, flags);
720 /* Change DTR and RTS */
721 if (on)
722 priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
723 else
724 priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
725 control = priv->line_control;
726 spin_unlock_irqrestore(&priv->lock, flags);
727 set_control_lines(port->serial->dev, control);
728}
729
730static void pl2303_close(struct usb_serial_port *port)
731{
732 struct pl2303_private *priv = usb_get_serial_port_data(port);
733 unsigned long flags;
Thiago Galesi572d3132006-07-29 10:46:37 -0300734
Harvey Harrison441b62c2008-03-03 16:08:34 -0800735 dbg("%s - port %d", __func__, port->number);
Thiago Galesi572d3132006-07-29 10:46:37 -0300736
Thiago Galesi572d3132006-07-29 10:46:37 -0300737 spin_lock_irqsave(&priv->lock, flags);
Thiago Galesi572d3132006-07-29 10:46:37 -0300738 /* clear out any remaining data in the buffer */
739 pl2303_buf_clear(priv->buf);
740 spin_unlock_irqrestore(&priv->lock, flags);
741
Thiago Galesi572d3132006-07-29 10:46:37 -0300742 /* shutdown our urbs */
Harvey Harrison441b62c2008-03-03 16:08:34 -0800743 dbg("%s - shutting down urbs", __func__);
Thiago Galesi572d3132006-07-29 10:46:37 -0300744 usb_kill_urb(port->write_urb);
745 usb_kill_urb(port->read_urb);
746 usb_kill_urb(port->interrupt_in_urb);
747
Thiago Galesi572d3132006-07-29 10:46:37 -0300748}
749
Alan Coxa509a7e2009-09-19 13:13:26 -0700750static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
Alan Cox606d0992006-12-08 02:38:45 -0800752 struct ktermios tmp_termios;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 struct usb_serial *serial = port->serial;
754 struct pl2303_private *priv = usb_get_serial_port_data(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 int result;
756
Harvey Harrison441b62c2008-03-03 16:08:34 -0800757 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758
Dariusz M16948992005-07-28 18:06:13 +0200759 if (priv->type != HX) {
760 usb_clear_halt(serial->dev, port->write_urb->pipe);
761 usb_clear_halt(serial->dev, port->read_urb->pipe);
Sarah Sharp3e152502007-12-14 14:08:35 -0800762 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 /* reset upstream data pipes */
Sarah Sharpeb44da02007-12-14 14:08:00 -0800764 pl2303_vendor_write(8, 0, serial);
765 pl2303_vendor_write(9, 0, serial);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 /* Setup termios */
Alan Cox95da3102008-07-22 11:09:07 +0100769 if (tty)
770 pl2303_set_termios(tty, port, &tmp_termios);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
Harvey Harrison441b62c2008-03-03 16:08:34 -0800772 dbg("%s - submitting read urb", __func__);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300773 result = usb_submit_urb(port->read_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300775 dev_err(&port->dev, "%s - failed submitting read urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800776 " error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +0100777 pl2303_close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return -EPROTO;
779 }
780
Harvey Harrison441b62c2008-03-03 16:08:34 -0800781 dbg("%s - submitting interrupt urb", __func__);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300782 result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 if (result) {
Thiago Galesi372db8a2006-07-31 15:39:27 -0300784 dev_err(&port->dev, "%s - failed submitting interrupt urb,"
Harvey Harrison441b62c2008-03-03 16:08:34 -0800785 " error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +0100786 pl2303_close(port);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 return -EPROTO;
788 }
Alan Cox335f8512009-06-11 12:26:29 +0100789 port->port.drain_delay = 256;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 return 0;
791}
792
Alan Cox95da3102008-07-22 11:09:07 +0100793static int pl2303_tiocmset(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300794 unsigned int set, unsigned int clear)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
Alan Cox95da3102008-07-22 11:09:07 +0100796 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 struct pl2303_private *priv = usb_get_serial_port_data(port);
798 unsigned long flags;
799 u8 control;
800
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700801 if (!usb_get_intfdata(port->serial->interface))
802 return -ENODEV;
803
Thiago Galesi372db8a2006-07-31 15:39:27 -0300804 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 if (set & TIOCM_RTS)
806 priv->line_control |= CONTROL_RTS;
807 if (set & TIOCM_DTR)
808 priv->line_control |= CONTROL_DTR;
809 if (clear & TIOCM_RTS)
810 priv->line_control &= ~CONTROL_RTS;
811 if (clear & TIOCM_DTR)
812 priv->line_control &= ~CONTROL_DTR;
813 control = priv->line_control;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300814 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
Thiago Galesi372db8a2006-07-31 15:39:27 -0300816 return set_control_lines(port->serial->dev, control);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817}
818
Alan Cox95da3102008-07-22 11:09:07 +0100819static int pl2303_tiocmget(struct tty_struct *tty, struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
Alan Cox95da3102008-07-22 11:09:07 +0100821 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 struct pl2303_private *priv = usb_get_serial_port_data(port);
823 unsigned long flags;
824 unsigned int mcr;
825 unsigned int status;
826 unsigned int result;
827
Harvey Harrison441b62c2008-03-03 16:08:34 -0800828 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Flavio Leitner6fdd8e82005-04-18 17:39:31 -0700830 if (!usb_get_intfdata(port->serial->interface))
831 return -ENODEV;
832
Thiago Galesi372db8a2006-07-31 15:39:27 -0300833 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 mcr = priv->line_control;
835 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300836 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
838 result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
839 | ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
840 | ((status & UART_CTS) ? TIOCM_CTS : 0)
841 | ((status & UART_DSR) ? TIOCM_DSR : 0)
842 | ((status & UART_RING) ? TIOCM_RI : 0)
843 | ((status & UART_DCD) ? TIOCM_CD : 0);
844
Harvey Harrison441b62c2008-03-03 16:08:34 -0800845 dbg("%s - result = %x", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
847 return result;
848}
849
Alan Cox335f8512009-06-11 12:26:29 +0100850static int pl2303_carrier_raised(struct usb_serial_port *port)
851{
852 struct pl2303_private *priv = usb_get_serial_port_data(port);
853 if (priv->line_status & UART_DCD)
854 return 1;
855 return 0;
856}
857
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
859{
860 struct pl2303_private *priv = usb_get_serial_port_data(port);
861 unsigned long flags;
862 unsigned int prevstatus;
863 unsigned int status;
864 unsigned int changed;
865
Thiago Galesi372db8a2006-07-31 15:39:27 -0300866 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 prevstatus = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300868 spin_unlock_irqrestore(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
870 while (1) {
871 interruptible_sleep_on(&priv->delta_msr_wait);
872 /* see if a signal did it */
873 if (signal_pending(current))
874 return -ERESTARTSYS;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300875
876 spin_lock_irqsave(&priv->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 status = priv->line_status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300878 spin_unlock_irqrestore(&priv->lock, flags);
879
Alan Cox3a0f43e2008-07-22 11:14:49 +0100880 changed = prevstatus ^ status;
Thiago Galesi372db8a2006-07-31 15:39:27 -0300881
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
883 ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
884 ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
Alan Cox3a0f43e2008-07-22 11:14:49 +0100885 ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886 return 0;
887 }
888 prevstatus = status;
889 }
890 /* NOTREACHED */
891 return 0;
892}
893
Alan Cox95da3102008-07-22 11:09:07 +0100894static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
Thiago Galesi372db8a2006-07-31 15:39:27 -0300895 unsigned int cmd, unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896{
John Tsiombikas67b99462010-02-25 17:09:08 +0200897 struct serial_struct ser;
Alan Cox95da3102008-07-22 11:09:07 +0100898 struct usb_serial_port *port = tty->driver_data;
Harvey Harrison441b62c2008-03-03 16:08:34 -0800899 dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900
901 switch (cmd) {
John Tsiombikas67b99462010-02-25 17:09:08 +0200902 case TIOCGSERIAL:
903 memset(&ser, 0, sizeof ser);
904 ser.type = PORT_16654;
905 ser.line = port->serial->minor;
906 ser.port = port->number;
907 ser.baud_base = 460800;
908
909 if (copy_to_user((void __user *)arg, &ser, sizeof ser))
910 return -EFAULT;
911
912 return 0;
913
Alan Cox3a0f43e2008-07-22 11:14:49 +0100914 case TIOCMIWAIT:
915 dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
916 return wait_modem_info(port, arg);
917 default:
918 dbg("%s not supported = 0x%04x", __func__, cmd);
919 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 return -ENOIOCTLCMD;
922}
923
Alan Cox95da3102008-07-22 11:09:07 +0100924static void pl2303_break_ctl(struct tty_struct *tty, int break_state)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
Alan Cox95da3102008-07-22 11:09:07 +0100926 struct usb_serial_port *port = tty->driver_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 struct usb_serial *serial = port->serial;
928 u16 state;
929 int result;
930
Harvey Harrison441b62c2008-03-03 16:08:34 -0800931 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932
933 if (break_state == 0)
934 state = BREAK_OFF;
935 else
936 state = BREAK_ON;
Alan Cox3a0f43e2008-07-22 11:14:49 +0100937 dbg("%s - turning break %s", __func__,
938 state == BREAK_OFF ? "off" : "on");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
Thiago Galesi372db8a2006-07-31 15:39:27 -0300940 result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
941 BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
942 0, NULL, 0, 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 if (result)
Harvey Harrison441b62c2008-03-03 16:08:34 -0800944 dbg("%s - error sending break = %d", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945}
946
Alan Sternf9c99bb2009-06-02 11:53:55 -0400947static void pl2303_release(struct usb_serial *serial)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948{
949 int i;
950 struct pl2303_private *priv;
951
Harvey Harrison441b62c2008-03-03 16:08:34 -0800952 dbg("%s", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953
954 for (i = 0; i < serial->num_ports; ++i) {
955 priv = usb_get_serial_port_data(serial->port[i]);
956 if (priv) {
957 pl2303_buf_free(priv->buf);
958 kfree(priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 }
Thiago Galesi372db8a2006-07-31 15:39:27 -0300960 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700961}
962
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700963static void pl2303_update_line_status(struct usb_serial_port *port,
964 unsigned char *data,
965 unsigned int actual_length)
966{
967
968 struct pl2303_private *priv = usb_get_serial_port_data(port);
969 unsigned long flags;
970 u8 status_idx = UART_STATE;
Horst Schirmeier95f209f2005-07-28 15:32:20 +0200971 u8 length = UART_STATE + 1;
Thiago Galesi9c537612006-07-29 10:47:12 -0300972 u16 idv, idp;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700973
Thiago Galesi9c537612006-07-29 10:47:12 -0300974 idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
975 idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
976
977
978 if (idv == SIEMENS_VENDOR_ID) {
979 if (idp == SIEMENS_PRODUCT_ID_X65 ||
980 idp == SIEMENS_PRODUCT_ID_SX1 ||
981 idp == SIEMENS_PRODUCT_ID_X75) {
982
983 length = 1;
984 status_idx = 0;
985 }
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700986 }
987
988 if (actual_length < length)
Luiz Fernando N. Capitulinoa009b752006-07-25 16:58:30 -0300989 return;
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700990
Alan Cox3a0f43e2008-07-22 11:14:49 +0100991 /* Save off the uart status for others to look at */
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700992 spin_lock_irqsave(&priv->lock, flags);
993 priv->line_status = data[status_idx];
994 spin_unlock_irqrestore(&priv->lock, flags);
Jason Wessel430eb0d2009-05-29 13:34:16 -0500995 if (priv->line_status & UART_BREAK_ERROR)
996 usb_serial_handle_break(port);
Thiago Galesi372db8a2006-07-31 15:39:27 -0300997 wake_up_interruptible(&priv->delta_msr_wait);
Flavio Leitner97bb13e2005-04-18 17:39:31 -0700998}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
David Howells7d12e782006-10-05 14:55:46 +01001000static void pl2303_read_int_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001{
Ming Leicdc97792008-02-24 18:41:47 +08001002 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 unsigned char *data = urb->transfer_buffer;
Flavio Leitner97bb13e2005-04-18 17:39:31 -07001004 unsigned int actual_length = urb->actual_length;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001005 int status = urb->status;
1006 int retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
Harvey Harrison441b62c2008-03-03 16:08:34 -08001008 dbg("%s (%d)", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001010 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 case 0:
1012 /* success */
1013 break;
1014 case -ECONNRESET:
1015 case -ENOENT:
1016 case -ESHUTDOWN:
1017 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001018 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001019 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 return;
1021 default:
Harvey Harrison441b62c2008-03-03 16:08:34 -08001022 dbg("%s - nonzero urb status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001023 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024 goto exit;
1025 }
1026
Harvey Harrison441b62c2008-03-03 16:08:34 -08001027 usb_serial_debug_data(debug, &port->dev, __func__,
Thiago Galesi372db8a2006-07-31 15:39:27 -03001028 urb->actual_length, urb->transfer_buffer);
1029
Flavio Leitner97bb13e2005-04-18 17:39:31 -07001030 pl2303_update_line_status(port, data, actual_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032exit:
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001033 retval = usb_submit_urb(urb, GFP_ATOMIC);
1034 if (retval)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001035 dev_err(&urb->dev->dev,
1036 "%s - usb_submit_urb failed with result %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001037 __func__, retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038}
1039
Alan Coxd4fc4a72009-07-09 13:36:58 +01001040static void pl2303_push_data(struct tty_struct *tty,
1041 struct usb_serial_port *port, struct urb *urb,
1042 u8 line_status)
1043{
1044 unsigned char *data = urb->transfer_buffer;
1045 /* get tty_flag from status */
1046 char tty_flag = TTY_NORMAL;
1047 /* break takes precedence over parity, */
1048 /* which takes precedence over framing errors */
1049 if (line_status & UART_BREAK_ERROR)
1050 tty_flag = TTY_BREAK;
1051 else if (line_status & UART_PARITY_ERROR)
1052 tty_flag = TTY_PARITY;
1053 else if (line_status & UART_FRAME_ERROR)
1054 tty_flag = TTY_FRAME;
1055 dbg("%s - tty_flag = %d", __func__, tty_flag);
1056
Alan Coxd4fc4a72009-07-09 13:36:58 +01001057 /* overrun is special, not associated with a char */
1058 if (line_status & UART_OVERRUN_ERROR)
1059 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
Johan Hovold9388e2e2009-10-08 11:36:46 +02001060
Jason Wesselbd5afa92010-03-08 21:50:12 -06001061 if (tty_flag == TTY_NORMAL && !(port->port.console && port->sysrq))
Johan Hovold9388e2e2009-10-08 11:36:46 +02001062 tty_insert_flip_string(tty, data, urb->actual_length);
1063 else {
Alan Coxd4fc4a72009-07-09 13:36:58 +01001064 int i;
1065 for (i = 0; i < urb->actual_length; ++i)
1066 if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
1067 tty_insert_flip_char(tty, data[i], tty_flag);
Johan Hovold9388e2e2009-10-08 11:36:46 +02001068 }
Alan Coxd4fc4a72009-07-09 13:36:58 +01001069 tty_flip_buffer_push(tty);
1070}
1071
David Howells7d12e782006-10-05 14:55:46 +01001072static void pl2303_read_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073{
Ming Leicdc97792008-02-24 18:41:47 +08001074 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 struct pl2303_private *priv = usb_get_serial_port_data(port);
1076 struct tty_struct *tty;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001079 int status = urb->status;
1080 u8 line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Harvey Harrison441b62c2008-03-03 16:08:34 -08001082 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001084 if (status) {
Harvey Harrison441b62c2008-03-03 16:08:34 -08001085 dbg("%s - urb status = %d", __func__, status);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001086 if (status == -EPROTO) {
Thiago Galesi372db8a2006-07-31 15:39:27 -03001087 /* PL2303 mysteriously fails with -EPROTO reschedule
1088 * the read */
1089 dbg("%s - caught -EPROTO, resubmitting the urb",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001090 __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 result = usb_submit_urb(urb, GFP_ATOMIC);
1092 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001093 dev_err(&urb->dev->dev, "%s - failed"
1094 " resubmitting read urb, error %d\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -08001095 __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 return;
1097 }
Harvey Harrison441b62c2008-03-03 16:08:34 -08001098 dbg("%s - unable to handle the error, exiting.", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 return;
1100 }
1101
Harvey Harrison441b62c2008-03-03 16:08:34 -08001102 usb_serial_debug_data(debug, &port->dev, __func__,
Alan Coxd4fc4a72009-07-09 13:36:58 +01001103 urb->actual_length, urb->transfer_buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104
1105 spin_lock_irqsave(&priv->lock, flags);
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001106 line_status = priv->line_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
1108 spin_unlock_irqrestore(&priv->lock, flags);
Thiago Galesi372db8a2006-07-31 15:39:27 -03001109 wake_up_interruptible(&priv->delta_msr_wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
Alan Cox4a90f092008-10-13 10:39:46 +01001111 tty = tty_port_tty_get(&port->port);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 if (tty && urb->actual_length) {
Alan Coxd4fc4a72009-07-09 13:36:58 +01001113 pl2303_push_data(tty, port, urb, line_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 }
Alan Cox4a90f092008-10-13 10:39:46 +01001115 tty_kref_put(tty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 /* Schedule the next read _if_ we are still open */
Alan Stern1f871582010-02-17 10:05:47 -05001117 result = usb_submit_urb(urb, GFP_ATOMIC);
1118 if (result && result != -EPERM)
1119 dev_err(&urb->dev->dev, "%s - failed resubmitting"
1120 " read urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121}
1122
David Howells7d12e782006-10-05 14:55:46 +01001123static void pl2303_write_bulk_callback(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124{
Ming Leicdc97792008-02-24 18:41:47 +08001125 struct usb_serial_port *port = urb->context;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 struct pl2303_private *priv = usb_get_serial_port_data(port);
1127 int result;
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001128 int status = urb->status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Harvey Harrison441b62c2008-03-03 16:08:34 -08001130 dbg("%s - port %d", __func__, port->number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001132 switch (status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 case 0:
1134 /* success */
1135 break;
1136 case -ECONNRESET:
1137 case -ENOENT:
1138 case -ESHUTDOWN:
1139 /* this urb is terminated, clean up */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001140 dbg("%s - urb shutting down with status: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001141 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 priv->write_urb_in_use = 0;
1143 return;
1144 default:
1145 /* error in the urb, so we have to resubmit it */
Harvey Harrison441b62c2008-03-03 16:08:34 -08001146 dbg("%s - Overflow in write", __func__);
1147 dbg("%s - nonzero write bulk status received: %d", __func__,
Greg Kroah-Hartman461d6962007-06-15 15:44:13 -07001148 status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 port->write_urb->transfer_buffer_length = 1;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001150 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 if (result)
Thiago Galesi372db8a2006-07-31 15:39:27 -03001152 dev_err(&urb->dev->dev, "%s - failed resubmitting write"
Harvey Harrison441b62c2008-03-03 16:08:34 -08001153 " urb, error %d\n", __func__, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 else
1155 return;
1156 }
1157
1158 priv->write_urb_in_use = 0;
1159
1160 /* send any buffered data */
1161 pl2303_send(port);
1162}
1163
Thiago Galesi572d3132006-07-29 10:46:37 -03001164/* All of the device info needed for the PL2303 SIO serial converter */
1165static struct usb_serial_driver pl2303_device = {
1166 .driver = {
1167 .owner = THIS_MODULE,
1168 .name = "pl2303",
1169 },
1170 .id_table = id_table,
Johannes Hölzld9b1b782006-12-17 21:50:24 +01001171 .usb_driver = &pl2303_driver,
Thiago Galesi572d3132006-07-29 10:46:37 -03001172 .num_ports = 1,
Johan Hovold3efeaff2010-03-17 23:00:40 +01001173 .bulk_out_size = 256,
Thiago Galesi572d3132006-07-29 10:46:37 -03001174 .open = pl2303_open,
1175 .close = pl2303_close,
Alan Cox335f8512009-06-11 12:26:29 +01001176 .dtr_rts = pl2303_dtr_rts,
1177 .carrier_raised = pl2303_carrier_raised,
Thiago Galesi572d3132006-07-29 10:46:37 -03001178 .write = pl2303_write,
1179 .ioctl = pl2303_ioctl,
1180 .break_ctl = pl2303_break_ctl,
1181 .set_termios = pl2303_set_termios,
1182 .tiocmget = pl2303_tiocmget,
1183 .tiocmset = pl2303_tiocmset,
1184 .read_bulk_callback = pl2303_read_bulk_callback,
1185 .read_int_callback = pl2303_read_int_callback,
1186 .write_bulk_callback = pl2303_write_bulk_callback,
1187 .write_room = pl2303_write_room,
1188 .chars_in_buffer = pl2303_chars_in_buffer,
1189 .attach = pl2303_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -04001190 .release = pl2303_release,
Thiago Galesi572d3132006-07-29 10:46:37 -03001191};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
Thiago Galesi372db8a2006-07-31 15:39:27 -03001193static int __init pl2303_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194{
1195 int retval;
Thiago Galesi372db8a2006-07-31 15:39:27 -03001196
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 retval = usb_serial_register(&pl2303_device);
1198 if (retval)
1199 goto failed_usb_serial_register;
1200 retval = usb_register(&pl2303_driver);
1201 if (retval)
1202 goto failed_usb_register;
Greg Kroah-Hartmanc197a8d2008-08-18 13:21:04 -07001203 printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 return 0;
1205failed_usb_register:
1206 usb_serial_deregister(&pl2303_device);
1207failed_usb_serial_register:
1208 return retval;
1209}
1210
Thiago Galesi372db8a2006-07-31 15:39:27 -03001211static void __exit pl2303_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212{
Thiago Galesi372db8a2006-07-31 15:39:27 -03001213 usb_deregister(&pl2303_driver);
1214 usb_serial_deregister(&pl2303_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215}
1216
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217module_init(pl2303_init);
1218module_exit(pl2303_exit);
1219
1220MODULE_DESCRIPTION(DRIVER_DESC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221MODULE_LICENSE("GPL");
1222
1223module_param(debug, bool, S_IRUGO | S_IWUSR);
1224MODULE_PARM_DESC(debug, "Debug enabled or not");
1225