diff options
Diffstat (limited to 'drivers/usb/serial/mos7720.c')
-rw-r--r-- | drivers/usb/serial/mos7720.c | 1683 |
1 files changed, 1683 insertions, 0 deletions
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c new file mode 100644 index 000000000000..82cd15b894b0 --- /dev/null +++ b/drivers/usb/serial/mos7720.c | |||
@@ -0,0 +1,1683 @@ | |||
1 | /* | ||
2 | * mos7720.c | ||
3 | * Controls the Moschip 7720 usb to dual port serial convertor | ||
4 | * | ||
5 | * Copyright 2006 Moschip Semiconductor Tech. Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation, version 2 of the License. | ||
10 | * | ||
11 | * Developed by: | ||
12 | * VijayaKumar.G.N. <vijaykumar@aspirecom.net> | ||
13 | * AjayKumar <ajay@aspirecom.net> | ||
14 | * Gurudeva.N. <gurudev@aspirecom.net> | ||
15 | * | ||
16 | * Cleaned up from the original by: | ||
17 | * Greg Kroah-Hartman <gregkh@suse.de> | ||
18 | * | ||
19 | * Originally based on drivers/usb/serial/io_edgeport.c which is: | ||
20 | * Copyright (C) 2000 Inside Out Networks, All rights reserved. | ||
21 | * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> | ||
22 | */ | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/errno.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/tty.h> | ||
28 | #include <linux/tty_driver.h> | ||
29 | #include <linux/tty_flip.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/serial.h> | ||
33 | #include <linux/serial_reg.h> | ||
34 | #include <linux/usb.h> | ||
35 | #include <linux/usb/serial.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | |||
38 | |||
39 | /* | ||
40 | * Version Information | ||
41 | */ | ||
42 | #define DRIVER_VERSION "1.0.0.4F" | ||
43 | #define DRIVER_AUTHOR "Aspire Communications pvt Ltd." | ||
44 | #define DRIVER_DESC "Moschip USB Serial Driver" | ||
45 | |||
46 | /* default urb timeout */ | ||
47 | #define MOS_WDR_TIMEOUT (HZ * 5) | ||
48 | |||
49 | #define MOS_PORT1 0x0200 | ||
50 | #define MOS_PORT2 0x0300 | ||
51 | #define MOS_VENREG 0x0000 | ||
52 | #define MOS_MAX_PORT 0x02 | ||
53 | #define MOS_WRITE 0x0E | ||
54 | #define MOS_READ 0x0D | ||
55 | |||
56 | /* Interrupt Rotinue Defines */ | ||
57 | #define SERIAL_IIR_RLS 0x06 | ||
58 | #define SERIAL_IIR_RDA 0x04 | ||
59 | #define SERIAL_IIR_CTI 0x0c | ||
60 | #define SERIAL_IIR_THR 0x02 | ||
61 | #define SERIAL_IIR_MS 0x00 | ||
62 | |||
63 | #define NUM_URBS 16 /* URB Count */ | ||
64 | #define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ | ||
65 | |||
66 | /* This structure holds all of the local port information */ | ||
67 | struct moschip_port | ||
68 | { | ||
69 | __u8 shadowLCR; /* last LCR value received */ | ||
70 | __u8 shadowMCR; /* last MCR value received */ | ||
71 | __u8 shadowMSR; /* last MSR value received */ | ||
72 | char open; | ||
73 | struct async_icount icount; | ||
74 | struct usb_serial_port *port; /* loop back to the owner */ | ||
75 | struct urb *write_urb_pool[NUM_URBS]; | ||
76 | }; | ||
77 | |||
78 | /* This structure holds all of the individual serial device information */ | ||
79 | struct moschip_serial | ||
80 | { | ||
81 | int interrupt_started; | ||
82 | }; | ||
83 | |||
84 | static int debug; | ||
85 | |||
86 | #define USB_VENDOR_ID_MOSCHIP 0x9710 | ||
87 | #define MOSCHIP_DEVICE_ID_7720 0x7720 | ||
88 | #define MOSCHIP_DEVICE_ID_7715 0x7715 | ||
89 | |||
90 | static struct usb_device_id moschip_port_id_table [] = { | ||
91 | { USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) }, | ||
92 | { } /* terminating entry */ | ||
93 | }; | ||
94 | MODULE_DEVICE_TABLE(usb, moschip_port_id_table); | ||
95 | |||
96 | |||
97 | /* | ||
98 | * mos7720_interrupt_callback | ||
99 | * this is the callback function for when we have received data on the | ||
100 | * interrupt endpoint. | ||
101 | */ | ||
102 | static void mos7720_interrupt_callback(struct urb *urb) | ||
103 | { | ||
104 | int result; | ||
105 | int length; | ||
106 | __u32 *data; | ||
107 | unsigned int status; | ||
108 | __u8 sp1; | ||
109 | __u8 sp2; | ||
110 | __u8 st; | ||
111 | |||
112 | dbg("%s"," : Entering\n"); | ||
113 | |||
114 | if (!urb) { | ||
115 | dbg("%s","Invalid Pointer !!!!:\n"); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | switch (urb->status) { | ||
120 | case 0: | ||
121 | /* success */ | ||
122 | break; | ||
123 | case -ECONNRESET: | ||
124 | case -ENOENT: | ||
125 | case -ESHUTDOWN: | ||
126 | /* this urb is terminated, clean up */ | ||
127 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, | ||
128 | urb->status); | ||
129 | return; | ||
130 | default: | ||
131 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, | ||
132 | urb->status); | ||
133 | goto exit; | ||
134 | } | ||
135 | |||
136 | length = urb->actual_length; | ||
137 | data = urb->transfer_buffer; | ||
138 | |||
139 | /* Moschip get 4 bytes | ||
140 | * Byte 1 IIR Port 1 (port.number is 0) | ||
141 | * Byte 2 IIR Port 2 (port.number is 1) | ||
142 | * Byte 3 -------------- | ||
143 | * Byte 4 FIFO status for both */ | ||
144 | if (length && length > 4) { | ||
145 | dbg("Wrong data !!!"); | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | status = *data; | ||
150 | |||
151 | sp1 = (status & 0xff000000)>>24; | ||
152 | sp2 = (status & 0x00ff0000)>>16; | ||
153 | st = status & 0x000000ff; | ||
154 | |||
155 | if ((sp1 & 0x01) || (sp2 & 0x01)) { | ||
156 | /* No Interrupt Pending in both the ports */ | ||
157 | dbg("No Interrupt !!!"); | ||
158 | } else { | ||
159 | switch (sp1 & 0x0f) { | ||
160 | case SERIAL_IIR_RLS: | ||
161 | dbg("Serial Port 1: Receiver status error or address " | ||
162 | "bit detected in 9-bit mode\n"); | ||
163 | break; | ||
164 | case SERIAL_IIR_CTI: | ||
165 | dbg("Serial Port 1: Receiver time out"); | ||
166 | break; | ||
167 | case SERIAL_IIR_MS: | ||
168 | dbg("Serial Port 1: Modem status change"); | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | switch (sp2 & 0x0f) { | ||
173 | case SERIAL_IIR_RLS: | ||
174 | dbg("Serial Port 2: Receiver status error or address " | ||
175 | "bit detected in 9-bit mode"); | ||
176 | break; | ||
177 | case SERIAL_IIR_CTI: | ||
178 | dbg("Serial Port 2: Receiver time out"); | ||
179 | break; | ||
180 | case SERIAL_IIR_MS: | ||
181 | dbg("Serial Port 2: Modem status change"); | ||
182 | break; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | exit: | ||
187 | result = usb_submit_urb(urb, GFP_ATOMIC); | ||
188 | if (result) | ||
189 | dev_err(&urb->dev->dev, | ||
190 | "%s - Error %d submitting control urb\n", | ||
191 | __FUNCTION__, result); | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * mos7720_bulk_in_callback | ||
197 | * this is the callback function for when we have received data on the | ||
198 | * bulk in endpoint. | ||
199 | */ | ||
200 | static void mos7720_bulk_in_callback(struct urb *urb) | ||
201 | { | ||
202 | int status; | ||
203 | unsigned char *data ; | ||
204 | struct usb_serial_port *port; | ||
205 | struct moschip_port *mos7720_port; | ||
206 | struct tty_struct *tty; | ||
207 | |||
208 | if (urb->status) { | ||
209 | dbg("nonzero read bulk status received: %d",urb->status); | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | mos7720_port = urb->context; | ||
214 | if (!mos7720_port) { | ||
215 | dbg("%s","NULL mos7720_port pointer \n"); | ||
216 | return ; | ||
217 | } | ||
218 | |||
219 | port = mos7720_port->port; | ||
220 | |||
221 | dbg("Entering...%s", __FUNCTION__); | ||
222 | |||
223 | data = urb->transfer_buffer; | ||
224 | |||
225 | tty = port->tty; | ||
226 | if (tty && urb->actual_length) { | ||
227 | tty_buffer_request_room(tty, urb->actual_length); | ||
228 | tty_insert_flip_string(tty, data, urb->actual_length); | ||
229 | tty_flip_buffer_push(tty); | ||
230 | } | ||
231 | |||
232 | if (!port->read_urb) { | ||
233 | dbg("URB KILLED !!!"); | ||
234 | return; | ||
235 | } | ||
236 | |||
237 | if (port->read_urb->status != -EINPROGRESS) { | ||
238 | port->read_urb->dev = port->serial->dev; | ||
239 | |||
240 | status = usb_submit_urb(port->read_urb, GFP_ATOMIC); | ||
241 | if (status) | ||
242 | dbg("usb_submit_urb(read bulk) failed, status = %d", | ||
243 | status); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | /* | ||
248 | * mos7720_bulk_out_data_callback | ||
249 | * this is the callback function for when we have finished sending serial | ||
250 | * data on the bulk out endpoint. | ||
251 | */ | ||
252 | static void mos7720_bulk_out_data_callback(struct urb *urb) | ||
253 | { | ||
254 | struct moschip_port *mos7720_port; | ||
255 | struct tty_struct *tty; | ||
256 | |||
257 | if (urb->status) { | ||
258 | dbg("nonzero write bulk status received:%d", urb->status); | ||
259 | return; | ||
260 | } | ||
261 | |||
262 | mos7720_port = urb->context; | ||
263 | if (!mos7720_port) { | ||
264 | dbg("NULL mos7720_port pointer"); | ||
265 | return ; | ||
266 | } | ||
267 | |||
268 | dbg("Entering ........."); | ||
269 | |||
270 | tty = mos7720_port->port->tty; | ||
271 | |||
272 | if (tty && mos7720_port->open) { | ||
273 | /* let the tty driver wakeup if it has a special * | ||
274 | * write_wakeup function */ | ||
275 | if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && | ||
276 | tty->ldisc.write_wakeup) | ||
277 | (tty->ldisc.write_wakeup)(tty); | ||
278 | |||
279 | /* tell the tty driver that something has changed */ | ||
280 | wake_up_interruptible(&tty->write_wait); | ||
281 | } | ||
282 | |||
283 | /* schedule_work(&mos7720_port->port->work); */ | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * send_mos_cmd | ||
288 | * this function will be used for sending command to device | ||
289 | */ | ||
290 | static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, | ||
291 | __u16 index, void *data) | ||
292 | { | ||
293 | int status; | ||
294 | unsigned int pipe; | ||
295 | u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); | ||
296 | __u8 requesttype; | ||
297 | __u16 size = 0x0000; | ||
298 | |||
299 | if (value < MOS_MAX_PORT) { | ||
300 | if (product == MOSCHIP_DEVICE_ID_7715) { | ||
301 | value = value*0x100+0x100; | ||
302 | } else { | ||
303 | value = value*0x100+0x200; | ||
304 | } | ||
305 | } else { | ||
306 | value = 0x0000; | ||
307 | if ((product == MOSCHIP_DEVICE_ID_7715) && | ||
308 | (index != 0x08)) { | ||
309 | dbg("serial->product== MOSCHIP_DEVICE_ID_7715"); | ||
310 | //index = 0x01 ; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | if (request == MOS_WRITE) { | ||
315 | request = (__u8)MOS_WRITE; | ||
316 | requesttype = (__u8)0x40; | ||
317 | value = value + (__u16)*((unsigned char *)data); | ||
318 | data = NULL; | ||
319 | pipe = usb_sndctrlpipe(serial->dev, 0); | ||
320 | } else { | ||
321 | request = (__u8)MOS_READ; | ||
322 | requesttype = (__u8)0xC0; | ||
323 | size = 0x01; | ||
324 | pipe = usb_rcvctrlpipe(serial->dev,0); | ||
325 | } | ||
326 | |||
327 | status = usb_control_msg(serial->dev, pipe, request, requesttype, | ||
328 | value, index, data, size, MOS_WDR_TIMEOUT); | ||
329 | |||
330 | if (status < 0) | ||
331 | dbg("Command Write failed Value %x index %x\n",value,index); | ||
332 | |||
333 | return status; | ||
334 | } | ||
335 | |||
336 | static int mos7720_open(struct usb_serial_port *port, struct file * filp) | ||
337 | { | ||
338 | struct usb_serial *serial; | ||
339 | struct usb_serial_port *port0; | ||
340 | struct urb *urb; | ||
341 | struct moschip_serial *mos7720_serial; | ||
342 | struct moschip_port *mos7720_port; | ||
343 | int response; | ||
344 | int port_number; | ||
345 | char data; | ||
346 | int j; | ||
347 | |||
348 | serial = port->serial; | ||
349 | |||
350 | mos7720_port = usb_get_serial_port_data(port); | ||
351 | if (mos7720_port == NULL) | ||
352 | return -ENODEV; | ||
353 | |||
354 | port0 = serial->port[0]; | ||
355 | |||
356 | mos7720_serial = usb_get_serial_data(serial); | ||
357 | |||
358 | if (mos7720_serial == NULL || port0 == NULL) | ||
359 | return -ENODEV; | ||
360 | |||
361 | usb_clear_halt(serial->dev, port->write_urb->pipe); | ||
362 | usb_clear_halt(serial->dev, port->read_urb->pipe); | ||
363 | |||
364 | /* Initialising the write urb pool */ | ||
365 | for (j = 0; j < NUM_URBS; ++j) { | ||
366 | urb = usb_alloc_urb(0,SLAB_ATOMIC); | ||
367 | mos7720_port->write_urb_pool[j] = urb; | ||
368 | |||
369 | if (urb == NULL) { | ||
370 | err("No more urbs???"); | ||
371 | continue; | ||
372 | } | ||
373 | |||
374 | urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, | ||
375 | GFP_KERNEL); | ||
376 | if (!urb->transfer_buffer) { | ||
377 | err("%s-out of memory for urb buffers.", __FUNCTION__); | ||
378 | continue; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | /* Initialize MCS7720 -- Write Init values to corresponding Registers | ||
383 | * | ||
384 | * Register Index | ||
385 | * 1 : IER | ||
386 | * 2 : FCR | ||
387 | * 3 : LCR | ||
388 | * 4 : MCR | ||
389 | * | ||
390 | * 0x08 : SP1/2 Control Reg | ||
391 | */ | ||
392 | port_number = port->number - port->serial->minor; | ||
393 | send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data); | ||
394 | dbg("SS::%p LSR:%x\n",mos7720_port, data); | ||
395 | |||
396 | dbg("Check:Sending Command .........."); | ||
397 | |||
398 | data = 0x02; | ||
399 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data); | ||
400 | data = 0x02; | ||
401 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data); | ||
402 | |||
403 | data = 0x00; | ||
404 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
405 | data = 0x00; | ||
406 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); | ||
407 | |||
408 | data = 0xCF; | ||
409 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); | ||
410 | data = 0x03; | ||
411 | mos7720_port->shadowLCR = data; | ||
412 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); | ||
413 | data = 0x0b; | ||
414 | mos7720_port->shadowMCR = data; | ||
415 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
416 | data = 0x0b; | ||
417 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
418 | |||
419 | data = 0x00; | ||
420 | send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); | ||
421 | data = 0x00; | ||
422 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); | ||
423 | |||
424 | /* data = 0x00; | ||
425 | send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data); | ||
426 | data = 0x03; | ||
427 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); | ||
428 | data = 0x00; | ||
429 | send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); | ||
430 | */ | ||
431 | data = 0x00; | ||
432 | send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); | ||
433 | |||
434 | data = data | (port->number - port->serial->minor + 1); | ||
435 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); | ||
436 | |||
437 | data = 0x83; | ||
438 | mos7720_port->shadowLCR = data; | ||
439 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); | ||
440 | data = 0x0c; | ||
441 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); | ||
442 | data = 0x00; | ||
443 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
444 | data = 0x03; | ||
445 | mos7720_port->shadowLCR = data; | ||
446 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); | ||
447 | data = 0x0c; | ||
448 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
449 | data = 0x0c; | ||
450 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
451 | |||
452 | //Matrix | ||
453 | |||
454 | /* force low_latency on so that our tty_push actually forces * | ||
455 | * the data through,otherwise it is scheduled, and with * | ||
456 | * high data rates (like with OHCI) data can get lost. */ | ||
457 | |||
458 | if (port->tty) | ||
459 | port->tty->low_latency = 1; | ||
460 | |||
461 | /* see if we've set up our endpoint info yet * | ||
462 | * (can't set it up in mos7720_startup as the * | ||
463 | * structures were not set up at that time.) */ | ||
464 | if (!mos7720_serial->interrupt_started) { | ||
465 | dbg("Interrupt buffer NULL !!!"); | ||
466 | |||
467 | /* not set up yet, so do it now */ | ||
468 | mos7720_serial->interrupt_started = 1; | ||
469 | |||
470 | dbg("To Submit URB !!!"); | ||
471 | |||
472 | /* set up our interrupt urb */ | ||
473 | usb_fill_int_urb(port0->interrupt_in_urb, serial->dev, | ||
474 | usb_rcvintpipe(serial->dev, | ||
475 | port->interrupt_in_endpointAddress), | ||
476 | port0->interrupt_in_buffer, | ||
477 | port0->interrupt_in_urb->transfer_buffer_length, | ||
478 | mos7720_interrupt_callback, mos7720_port, | ||
479 | port0->interrupt_in_urb->interval); | ||
480 | |||
481 | /* start interrupt read for this mos7720 this interrupt * | ||
482 | * will continue as long as the mos7720 is connected */ | ||
483 | dbg("Submit URB over !!!"); | ||
484 | response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL); | ||
485 | if (response) | ||
486 | dev_err(&port->dev, | ||
487 | "%s - Error %d submitting control urb", | ||
488 | __FUNCTION__, response); | ||
489 | } | ||
490 | |||
491 | /* set up our bulk in urb */ | ||
492 | usb_fill_bulk_urb(port->read_urb, serial->dev, | ||
493 | usb_rcvbulkpipe(serial->dev, | ||
494 | port->bulk_in_endpointAddress), | ||
495 | port->bulk_in_buffer, | ||
496 | port->read_urb->transfer_buffer_length, | ||
497 | mos7720_bulk_in_callback, mos7720_port); | ||
498 | response = usb_submit_urb(port->read_urb, GFP_KERNEL); | ||
499 | if (response) | ||
500 | dev_err(&port->dev, | ||
501 | "%s - Error %d submitting read urb", __FUNCTION__, response); | ||
502 | |||
503 | /* initialize our icount structure */ | ||
504 | memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount)); | ||
505 | |||
506 | /* initialize our port settings */ | ||
507 | mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */ | ||
508 | |||
509 | /* send a open port command */ | ||
510 | mos7720_port->open = 1; | ||
511 | |||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | * mos7720_chars_in_buffer | ||
517 | * this function is called by the tty driver when it wants to know how many | ||
518 | * bytes of data we currently have outstanding in the port (data that has | ||
519 | * been written, but hasn't made it out the port yet) | ||
520 | * If successful, we return the number of bytes left to be written in the | ||
521 | * system, | ||
522 | * Otherwise we return a negative error number. | ||
523 | */ | ||
524 | static int mos7720_chars_in_buffer(struct usb_serial_port *port) | ||
525 | { | ||
526 | int i; | ||
527 | int chars = 0; | ||
528 | struct moschip_port *mos7720_port; | ||
529 | |||
530 | dbg("%s:entering ...........", __FUNCTION__); | ||
531 | |||
532 | mos7720_port = usb_get_serial_port_data(port); | ||
533 | if (mos7720_port == NULL) { | ||
534 | dbg("%s:leaving ...........", __FUNCTION__); | ||
535 | return -ENODEV; | ||
536 | } | ||
537 | |||
538 | for (i = 0; i < NUM_URBS; ++i) { | ||
539 | if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) | ||
540 | chars += URB_TRANSFER_BUFFER_SIZE; | ||
541 | } | ||
542 | dbg("%s - returns %d", __FUNCTION__, chars); | ||
543 | return chars; | ||
544 | } | ||
545 | |||
546 | static void mos7720_close(struct usb_serial_port *port, struct file *filp) | ||
547 | { | ||
548 | struct usb_serial *serial; | ||
549 | struct moschip_port *mos7720_port; | ||
550 | char data; | ||
551 | int j; | ||
552 | |||
553 | dbg("mos7720_close:entering..."); | ||
554 | |||
555 | serial = port->serial; | ||
556 | |||
557 | mos7720_port = usb_get_serial_port_data(port); | ||
558 | if (mos7720_port == NULL) | ||
559 | return; | ||
560 | |||
561 | for (j = 0; j < NUM_URBS; ++j) | ||
562 | usb_kill_urb(mos7720_port->write_urb_pool[j]); | ||
563 | |||
564 | /* Freeing Write URBs */ | ||
565 | for (j = 0; j < NUM_URBS; ++j) { | ||
566 | if (mos7720_port->write_urb_pool[j]) { | ||
567 | kfree(mos7720_port->write_urb_pool[j]->transfer_buffer); | ||
568 | usb_free_urb(mos7720_port->write_urb_pool[j]); | ||
569 | } | ||
570 | } | ||
571 | |||
572 | /* While closing port, shutdown all bulk read, write * | ||
573 | * and interrupt read if they exists */ | ||
574 | if (serial->dev) { | ||
575 | dbg("Shutdown bulk write"); | ||
576 | usb_kill_urb(port->write_urb); | ||
577 | dbg("Shutdown bulk read"); | ||
578 | usb_kill_urb(port->read_urb); | ||
579 | } | ||
580 | |||
581 | data = 0x00; | ||
582 | send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, | ||
583 | 0x04, &data); | ||
584 | |||
585 | data = 0x00; | ||
586 | send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, | ||
587 | 0x01, &data); | ||
588 | |||
589 | mos7720_port->open = 0; | ||
590 | |||
591 | dbg("Leaving %s", __FUNCTION__); | ||
592 | } | ||
593 | |||
594 | static void mos7720_break(struct usb_serial_port *port, int break_state) | ||
595 | { | ||
596 | unsigned char data; | ||
597 | struct usb_serial *serial; | ||
598 | struct moschip_port *mos7720_port; | ||
599 | |||
600 | dbg("Entering %s", __FUNCTION__); | ||
601 | |||
602 | serial = port->serial; | ||
603 | |||
604 | mos7720_port = usb_get_serial_port_data(port); | ||
605 | if (mos7720_port == NULL) | ||
606 | return; | ||
607 | |||
608 | if (break_state == -1) | ||
609 | data = mos7720_port->shadowLCR | UART_LCR_SBC; | ||
610 | else | ||
611 | data = mos7720_port->shadowLCR & ~UART_LCR_SBC; | ||
612 | |||
613 | mos7720_port->shadowLCR = data; | ||
614 | send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, | ||
615 | 0x03, &data); | ||
616 | |||
617 | return; | ||
618 | } | ||
619 | |||
620 | /* | ||
621 | * mos7720_write_room | ||
622 | * this function is called by the tty driver when it wants to know how many | ||
623 | * bytes of data we can accept for a specific port. | ||
624 | * If successful, we return the amount of room that we have for this port | ||
625 | * Otherwise we return a negative error number. | ||
626 | */ | ||
627 | static int mos7720_write_room(struct usb_serial_port *port) | ||
628 | { | ||
629 | struct moschip_port *mos7720_port; | ||
630 | int room = 0; | ||
631 | int i; | ||
632 | |||
633 | dbg("%s:entering ...........", __FUNCTION__); | ||
634 | |||
635 | mos7720_port = usb_get_serial_port_data(port); | ||
636 | if (mos7720_port == NULL) { | ||
637 | dbg("%s:leaving ...........", __FUNCTION__); | ||
638 | return -ENODEV; | ||
639 | } | ||
640 | |||
641 | for (i = 0; i < NUM_URBS; ++i) { | ||
642 | if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) | ||
643 | room += URB_TRANSFER_BUFFER_SIZE; | ||
644 | } | ||
645 | |||
646 | dbg("%s - returns %d", __FUNCTION__, room); | ||
647 | return room; | ||
648 | } | ||
649 | |||
650 | static int mos7720_write(struct usb_serial_port *port, | ||
651 | const unsigned char *data, int count) | ||
652 | { | ||
653 | int status; | ||
654 | int i; | ||
655 | int bytes_sent = 0; | ||
656 | int transfer_size; | ||
657 | |||
658 | struct moschip_port *mos7720_port; | ||
659 | struct usb_serial *serial; | ||
660 | struct urb *urb; | ||
661 | const unsigned char *current_position = data; | ||
662 | |||
663 | dbg("%s:entering ...........", __FUNCTION__); | ||
664 | |||
665 | serial = port->serial; | ||
666 | |||
667 | mos7720_port = usb_get_serial_port_data(port); | ||
668 | if (mos7720_port == NULL) { | ||
669 | dbg("mos7720_port is NULL"); | ||
670 | return -ENODEV; | ||
671 | } | ||
672 | |||
673 | /* try to find a free urb in the list */ | ||
674 | urb = NULL; | ||
675 | |||
676 | for (i = 0; i < NUM_URBS; ++i) { | ||
677 | if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { | ||
678 | urb = mos7720_port->write_urb_pool[i]; | ||
679 | dbg("URB:%d",i); | ||
680 | break; | ||
681 | } | ||
682 | } | ||
683 | |||
684 | if (urb == NULL) { | ||
685 | dbg("%s - no more free urbs", __FUNCTION__); | ||
686 | goto exit; | ||
687 | } | ||
688 | |||
689 | if (urb->transfer_buffer == NULL) { | ||
690 | urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, | ||
691 | GFP_KERNEL); | ||
692 | if (urb->transfer_buffer == NULL) { | ||
693 | err("%s no more kernel memory...", __FUNCTION__); | ||
694 | goto exit; | ||
695 | } | ||
696 | } | ||
697 | transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE); | ||
698 | |||
699 | memcpy(urb->transfer_buffer, current_position, transfer_size); | ||
700 | usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, | ||
701 | urb->transfer_buffer); | ||
702 | |||
703 | /* fill urb with data and submit */ | ||
704 | usb_fill_bulk_urb(urb, serial->dev, | ||
705 | usb_sndbulkpipe(serial->dev, | ||
706 | port->bulk_out_endpointAddress), | ||
707 | urb->transfer_buffer, transfer_size, | ||
708 | mos7720_bulk_out_data_callback, mos7720_port); | ||
709 | |||
710 | /* send it down the pipe */ | ||
711 | status = usb_submit_urb(urb,GFP_ATOMIC); | ||
712 | if (status) { | ||
713 | err("%s - usb_submit_urb(write bulk) failed with status = %d", | ||
714 | __FUNCTION__, status); | ||
715 | bytes_sent = status; | ||
716 | goto exit; | ||
717 | } | ||
718 | bytes_sent = transfer_size; | ||
719 | |||
720 | exit: | ||
721 | return bytes_sent; | ||
722 | } | ||
723 | |||
724 | static void mos7720_throttle(struct usb_serial_port *port) | ||
725 | { | ||
726 | struct moschip_port *mos7720_port; | ||
727 | struct tty_struct *tty; | ||
728 | int status; | ||
729 | |||
730 | dbg("%s- port %d\n", __FUNCTION__, port->number); | ||
731 | |||
732 | mos7720_port = usb_get_serial_port_data(port); | ||
733 | |||
734 | if (mos7720_port == NULL) | ||
735 | return; | ||
736 | |||
737 | if (!mos7720_port->open) { | ||
738 | dbg("port not opened"); | ||
739 | return; | ||
740 | } | ||
741 | |||
742 | dbg("%s: Entering ..........", __FUNCTION__); | ||
743 | |||
744 | tty = port->tty; | ||
745 | if (!tty) { | ||
746 | dbg("%s - no tty available", __FUNCTION__); | ||
747 | return; | ||
748 | } | ||
749 | |||
750 | /* if we are implementing XON/XOFF, send the stop character */ | ||
751 | if (I_IXOFF(tty)) { | ||
752 | unsigned char stop_char = STOP_CHAR(tty); | ||
753 | status = mos7720_write(port, &stop_char, 1); | ||
754 | if (status <= 0) | ||
755 | return; | ||
756 | } | ||
757 | |||
758 | /* if we are implementing RTS/CTS, toggle that line */ | ||
759 | if (tty->termios->c_cflag & CRTSCTS) { | ||
760 | mos7720_port->shadowMCR &= ~UART_MCR_RTS; | ||
761 | status = send_mos_cmd(port->serial, MOS_WRITE, | ||
762 | port->number - port->serial->minor, | ||
763 | UART_MCR, &mos7720_port->shadowMCR); | ||
764 | if (status != 0) | ||
765 | return; | ||
766 | } | ||
767 | } | ||
768 | |||
769 | static void mos7720_unthrottle(struct usb_serial_port *port) | ||
770 | { | ||
771 | struct tty_struct *tty; | ||
772 | int status; | ||
773 | struct moschip_port *mos7720_port = usb_get_serial_port_data(port); | ||
774 | |||
775 | if (mos7720_port == NULL) | ||
776 | return; | ||
777 | |||
778 | if (!mos7720_port->open) { | ||
779 | dbg("%s - port not opened", __FUNCTION__); | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | dbg("%s: Entering ..........", __FUNCTION__); | ||
784 | |||
785 | tty = port->tty; | ||
786 | if (!tty) { | ||
787 | dbg("%s - no tty available", __FUNCTION__); | ||
788 | return; | ||
789 | } | ||
790 | |||
791 | /* if we are implementing XON/XOFF, send the start character */ | ||
792 | if (I_IXOFF(tty)) { | ||
793 | unsigned char start_char = START_CHAR(tty); | ||
794 | status = mos7720_write(port, &start_char, 1); | ||
795 | if (status <= 0) | ||
796 | return; | ||
797 | } | ||
798 | |||
799 | /* if we are implementing RTS/CTS, toggle that line */ | ||
800 | if (tty->termios->c_cflag & CRTSCTS) { | ||
801 | mos7720_port->shadowMCR |= UART_MCR_RTS; | ||
802 | status = send_mos_cmd(port->serial, MOS_WRITE, | ||
803 | port->number - port->serial->minor, | ||
804 | UART_MCR, &mos7720_port->shadowMCR); | ||
805 | if (status != 0) | ||
806 | return; | ||
807 | } | ||
808 | } | ||
809 | |||
810 | static int set_higher_rates(struct moschip_port *mos7720_port, | ||
811 | unsigned int baud) | ||
812 | { | ||
813 | unsigned char data; | ||
814 | struct usb_serial_port *port; | ||
815 | struct usb_serial *serial; | ||
816 | int port_number; | ||
817 | |||
818 | if (mos7720_port == NULL) | ||
819 | return -EINVAL; | ||
820 | |||
821 | port = mos7720_port->port; | ||
822 | serial = port->serial; | ||
823 | |||
824 | /*********************************************** | ||
825 | * Init Sequence for higher rates | ||
826 | ***********************************************/ | ||
827 | dbg("Sending Setting Commands .........."); | ||
828 | port_number = port->number - port->serial->minor; | ||
829 | |||
830 | data = 0x000; | ||
831 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
832 | data = 0x000; | ||
833 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); | ||
834 | data = 0x0CF; | ||
835 | send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data); | ||
836 | data = 0x00b; | ||
837 | mos7720_port->shadowMCR = data; | ||
838 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
839 | data = 0x00b; | ||
840 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
841 | |||
842 | data = 0x000; | ||
843 | send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); | ||
844 | data = 0x000; | ||
845 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); | ||
846 | |||
847 | |||
848 | /*********************************************** | ||
849 | * Set for higher rates * | ||
850 | ***********************************************/ | ||
851 | |||
852 | data = baud * 0x10; | ||
853 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data); | ||
854 | |||
855 | data = 0x003; | ||
856 | send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); | ||
857 | data = 0x003; | ||
858 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); | ||
859 | |||
860 | data = 0x02b; | ||
861 | mos7720_port->shadowMCR = data; | ||
862 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
863 | data = 0x02b; | ||
864 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
865 | |||
866 | /*********************************************** | ||
867 | * Set DLL/DLM | ||
868 | ***********************************************/ | ||
869 | |||
870 | data = mos7720_port->shadowLCR | UART_LCR_DLAB; | ||
871 | mos7720_port->shadowLCR = data; | ||
872 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); | ||
873 | |||
874 | data = 0x001; /* DLL */ | ||
875 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); | ||
876 | data = 0x000; /* DLM */ | ||
877 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); | ||
878 | |||
879 | data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; | ||
880 | mos7720_port->shadowLCR = data; | ||
881 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); | ||
882 | |||
883 | return 0; | ||
884 | } | ||
885 | |||
886 | /* baud rate information */ | ||
887 | struct divisor_table_entry | ||
888 | { | ||
889 | __u32 baudrate; | ||
890 | __u16 divisor; | ||
891 | }; | ||
892 | |||
893 | /* Define table of divisors for moschip 7720 hardware * | ||
894 | * These assume a 3.6864MHz crystal, the standard /16, and * | ||
895 | * MCR.7 = 0. */ | ||
896 | static struct divisor_table_entry divisor_table[] = { | ||
897 | { 50, 2304}, | ||
898 | { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */ | ||
899 | { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */ | ||
900 | { 150, 768}, | ||
901 | { 300, 384}, | ||
902 | { 600, 192}, | ||
903 | { 1200, 96}, | ||
904 | { 1800, 64}, | ||
905 | { 2400, 48}, | ||
906 | { 4800, 24}, | ||
907 | { 7200, 16}, | ||
908 | { 9600, 12}, | ||
909 | { 19200, 6}, | ||
910 | { 38400, 3}, | ||
911 | { 57600, 2}, | ||
912 | { 115200, 1}, | ||
913 | }; | ||
914 | |||
915 | /***************************************************************************** | ||
916 | * calc_baud_rate_divisor | ||
917 | * this function calculates the proper baud rate divisor for the specified | ||
918 | * baud rate. | ||
919 | *****************************************************************************/ | ||
920 | static int calc_baud_rate_divisor(int baudrate, int *divisor) | ||
921 | { | ||
922 | int i; | ||
923 | __u16 custom; | ||
924 | __u16 round1; | ||
925 | __u16 round; | ||
926 | |||
927 | |||
928 | dbg("%s - %d", __FUNCTION__, baudrate); | ||
929 | |||
930 | for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { | ||
931 | if (divisor_table[i].baudrate == baudrate) { | ||
932 | *divisor = divisor_table[i].divisor; | ||
933 | return 0; | ||
934 | } | ||
935 | } | ||
936 | |||
937 | /* After trying for all the standard baud rates * | ||
938 | * Try calculating the divisor for this baud rate */ | ||
939 | if (baudrate > 75 && baudrate < 230400) { | ||
940 | /* get the divisor */ | ||
941 | custom = (__u16)(230400L / baudrate); | ||
942 | |||
943 | /* Check for round off */ | ||
944 | round1 = (__u16)(2304000L / baudrate); | ||
945 | round = (__u16)(round1 - (custom * 10)); | ||
946 | if (round > 4) | ||
947 | custom++; | ||
948 | *divisor = custom; | ||
949 | |||
950 | dbg("Baud %d = %d",baudrate, custom); | ||
951 | return 0; | ||
952 | } | ||
953 | |||
954 | dbg("Baud calculation Failed..."); | ||
955 | return -EINVAL; | ||
956 | } | ||
957 | |||
958 | /* | ||
959 | * send_cmd_write_baud_rate | ||
960 | * this function sends the proper command to change the baud rate of the | ||
961 | * specified port. | ||
962 | */ | ||
963 | static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, | ||
964 | int baudrate) | ||
965 | { | ||
966 | struct usb_serial_port *port; | ||
967 | struct usb_serial *serial; | ||
968 | int divisor; | ||
969 | int status; | ||
970 | unsigned char data; | ||
971 | unsigned char number; | ||
972 | |||
973 | if (mos7720_port == NULL) | ||
974 | return -1; | ||
975 | |||
976 | port = mos7720_port->port; | ||
977 | serial = port->serial; | ||
978 | |||
979 | dbg("%s: Entering ..........", __FUNCTION__); | ||
980 | |||
981 | number = port->number - port->serial->minor; | ||
982 | dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate); | ||
983 | |||
984 | /* Calculate the Divisor */ | ||
985 | status = calc_baud_rate_divisor(baudrate, &divisor); | ||
986 | if (status) { | ||
987 | err("%s - bad baud rate", __FUNCTION__); | ||
988 | return status; | ||
989 | } | ||
990 | |||
991 | /* Enable access to divisor latch */ | ||
992 | data = mos7720_port->shadowLCR | UART_LCR_DLAB; | ||
993 | mos7720_port->shadowLCR = data; | ||
994 | send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data); | ||
995 | |||
996 | /* Write the divisor */ | ||
997 | data = ((unsigned char)(divisor & 0xff)); | ||
998 | send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data); | ||
999 | |||
1000 | data = ((unsigned char)((divisor & 0xff00) >> 8)); | ||
1001 | send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data); | ||
1002 | |||
1003 | /* Disable access to divisor latch */ | ||
1004 | data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; | ||
1005 | mos7720_port->shadowLCR = data; | ||
1006 | send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data); | ||
1007 | |||
1008 | return status; | ||
1009 | } | ||
1010 | |||
1011 | /* | ||
1012 | * change_port_settings | ||
1013 | * This routine is called to set the UART on the device to match | ||
1014 | * the specified new settings. | ||
1015 | */ | ||
1016 | static void change_port_settings(struct moschip_port *mos7720_port, | ||
1017 | struct termios *old_termios) | ||
1018 | { | ||
1019 | struct usb_serial_port *port; | ||
1020 | struct usb_serial *serial; | ||
1021 | struct tty_struct *tty; | ||
1022 | int baud; | ||
1023 | unsigned cflag; | ||
1024 | unsigned iflag; | ||
1025 | __u8 mask = 0xff; | ||
1026 | __u8 lData; | ||
1027 | __u8 lParity; | ||
1028 | __u8 lStop; | ||
1029 | int status; | ||
1030 | int port_number; | ||
1031 | char data; | ||
1032 | |||
1033 | if (mos7720_port == NULL) | ||
1034 | return ; | ||
1035 | |||
1036 | port = mos7720_port->port; | ||
1037 | serial = port->serial; | ||
1038 | port_number = port->number - port->serial->minor; | ||
1039 | |||
1040 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
1041 | |||
1042 | if (!mos7720_port->open) { | ||
1043 | dbg("%s - port not opened", __FUNCTION__); | ||
1044 | return; | ||
1045 | } | ||
1046 | |||
1047 | tty = mos7720_port->port->tty; | ||
1048 | |||
1049 | if ((!tty) || (!tty->termios)) { | ||
1050 | dbg("%s - no tty structures", __FUNCTION__); | ||
1051 | return; | ||
1052 | } | ||
1053 | |||
1054 | dbg("%s: Entering ..........", __FUNCTION__); | ||
1055 | |||
1056 | lData = UART_LCR_WLEN8; | ||
1057 | lStop = 0x00; /* 1 stop bit */ | ||
1058 | lParity = 0x00; /* No parity */ | ||
1059 | |||
1060 | cflag = tty->termios->c_cflag; | ||
1061 | iflag = tty->termios->c_iflag; | ||
1062 | |||
1063 | /* Change the number of bits */ | ||
1064 | switch (cflag & CSIZE) { | ||
1065 | case CS5: | ||
1066 | lData = UART_LCR_WLEN5; | ||
1067 | mask = 0x1f; | ||
1068 | break; | ||
1069 | |||
1070 | case CS6: | ||
1071 | lData = UART_LCR_WLEN6; | ||
1072 | mask = 0x3f; | ||
1073 | break; | ||
1074 | |||
1075 | case CS7: | ||
1076 | lData = UART_LCR_WLEN7; | ||
1077 | mask = 0x7f; | ||
1078 | break; | ||
1079 | default: | ||
1080 | case CS8: | ||
1081 | lData = UART_LCR_WLEN8; | ||
1082 | break; | ||
1083 | } | ||
1084 | |||
1085 | /* Change the Parity bit */ | ||
1086 | if (cflag & PARENB) { | ||
1087 | if (cflag & PARODD) { | ||
1088 | lParity = UART_LCR_PARITY; | ||
1089 | dbg("%s - parity = odd", __FUNCTION__); | ||
1090 | } else { | ||
1091 | lParity = (UART_LCR_EPAR | UART_LCR_PARITY); | ||
1092 | dbg("%s - parity = even", __FUNCTION__); | ||
1093 | } | ||
1094 | |||
1095 | } else { | ||
1096 | dbg("%s - parity = none", __FUNCTION__); | ||
1097 | } | ||
1098 | |||
1099 | if (cflag & CMSPAR) | ||
1100 | lParity = lParity | 0x20; | ||
1101 | |||
1102 | /* Change the Stop bit */ | ||
1103 | if (cflag & CSTOPB) { | ||
1104 | lStop = UART_LCR_STOP; | ||
1105 | dbg("%s - stop bits = 2", __FUNCTION__); | ||
1106 | } else { | ||
1107 | lStop = 0x00; | ||
1108 | dbg("%s - stop bits = 1", __FUNCTION__); | ||
1109 | } | ||
1110 | |||
1111 | #define LCR_BITS_MASK 0x03 /* Mask for bits/char field */ | ||
1112 | #define LCR_STOP_MASK 0x04 /* Mask for stop bits field */ | ||
1113 | #define LCR_PAR_MASK 0x38 /* Mask for parity field */ | ||
1114 | |||
1115 | /* Update the LCR with the correct value */ | ||
1116 | mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); | ||
1117 | mos7720_port->shadowLCR |= (lData | lParity | lStop); | ||
1118 | |||
1119 | |||
1120 | /* Disable Interrupts */ | ||
1121 | data = 0x00; | ||
1122 | send_mos_cmd(serial,MOS_WRITE,port->number - port->serial->minor, UART_IER, &data); | ||
1123 | |||
1124 | data = 0x00; | ||
1125 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); | ||
1126 | |||
1127 | data = 0xcf; | ||
1128 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); | ||
1129 | |||
1130 | /* Send the updated LCR value to the mos7720 */ | ||
1131 | data = mos7720_port->shadowLCR; | ||
1132 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data); | ||
1133 | |||
1134 | data = 0x00b; | ||
1135 | mos7720_port->shadowMCR = data; | ||
1136 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
1137 | data = 0x00b; | ||
1138 | send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); | ||
1139 | |||
1140 | /* set up the MCR register and send it to the mos7720 */ | ||
1141 | mos7720_port->shadowMCR = UART_MCR_OUT2; | ||
1142 | if (cflag & CBAUD) | ||
1143 | mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS); | ||
1144 | |||
1145 | if (cflag & CRTSCTS) { | ||
1146 | mos7720_port->shadowMCR |= (UART_MCR_XONANY); | ||
1147 | |||
1148 | /* To set hardware flow control to the specified * | ||
1149 | * serial port, in SP1/2_CONTROL_REG */ | ||
1150 | if (port->number) { | ||
1151 | data = 0x001; | ||
1152 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, | ||
1153 | 0x08, &data); | ||
1154 | } else { | ||
1155 | data = 0x002; | ||
1156 | send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, | ||
1157 | 0x08, &data); | ||
1158 | } | ||
1159 | } else { | ||
1160 | mos7720_port->shadowMCR &= ~(UART_MCR_XONANY); | ||
1161 | } | ||
1162 | |||
1163 | data = mos7720_port->shadowMCR; | ||
1164 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data); | ||
1165 | |||
1166 | /* Determine divisor based on baud rate */ | ||
1167 | baud = tty_get_baud_rate(tty); | ||
1168 | if (!baud) { | ||
1169 | /* pick a default, any default... */ | ||
1170 | dbg("Picked default baud..."); | ||
1171 | baud = 9600; | ||
1172 | } | ||
1173 | |||
1174 | if (baud >= 230400) { | ||
1175 | set_higher_rates(mos7720_port, baud); | ||
1176 | /* Enable Interrupts */ | ||
1177 | data = 0x0c; | ||
1178 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); | ||
1179 | return; | ||
1180 | } | ||
1181 | |||
1182 | dbg("%s - baud rate = %d", __FUNCTION__, baud); | ||
1183 | status = send_cmd_write_baud_rate(mos7720_port, baud); | ||
1184 | |||
1185 | /* Enable Interrupts */ | ||
1186 | data = 0x0c; | ||
1187 | send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); | ||
1188 | |||
1189 | if (port->read_urb->status != -EINPROGRESS) { | ||
1190 | port->read_urb->dev = serial->dev; | ||
1191 | |||
1192 | status = usb_submit_urb(port->read_urb, GFP_ATOMIC); | ||
1193 | if (status) | ||
1194 | dbg("usb_submit_urb(read bulk) failed, status = %d", | ||
1195 | status); | ||
1196 | } | ||
1197 | return; | ||
1198 | } | ||
1199 | |||
1200 | /* | ||
1201 | * mos7720_set_termios | ||
1202 | * this function is called by the tty driver when it wants to change the | ||
1203 | * termios structure. | ||
1204 | */ | ||
1205 | static void mos7720_set_termios(struct usb_serial_port *port, | ||
1206 | struct termios *old_termios) | ||
1207 | { | ||
1208 | int status; | ||
1209 | unsigned int cflag; | ||
1210 | struct usb_serial *serial; | ||
1211 | struct moschip_port *mos7720_port; | ||
1212 | struct tty_struct *tty; | ||
1213 | |||
1214 | serial = port->serial; | ||
1215 | |||
1216 | mos7720_port = usb_get_serial_port_data(port); | ||
1217 | |||
1218 | if (mos7720_port == NULL) | ||
1219 | return; | ||
1220 | |||
1221 | tty = port->tty; | ||
1222 | |||
1223 | if (!port->tty || !port->tty->termios) { | ||
1224 | dbg("%s - no tty or termios", __FUNCTION__); | ||
1225 | return; | ||
1226 | } | ||
1227 | |||
1228 | if (!mos7720_port->open) { | ||
1229 | dbg("%s - port not opened", __FUNCTION__); | ||
1230 | return; | ||
1231 | } | ||
1232 | |||
1233 | dbg("%s\n","setting termios - ASPIRE"); | ||
1234 | |||
1235 | cflag = tty->termios->c_cflag; | ||
1236 | |||
1237 | if (!cflag) { | ||
1238 | printk("%s %s\n",__FUNCTION__,"cflag is NULL"); | ||
1239 | return; | ||
1240 | } | ||
1241 | |||
1242 | /* check that they really want us to change something */ | ||
1243 | if (old_termios) { | ||
1244 | if ((cflag == old_termios->c_cflag) && | ||
1245 | (RELEVANT_IFLAG(tty->termios->c_iflag) == | ||
1246 | RELEVANT_IFLAG(old_termios->c_iflag))) { | ||
1247 | dbg("Nothing to change"); | ||
1248 | return; | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | dbg("%s - clfag %08x iflag %08x", __FUNCTION__, | ||
1253 | tty->termios->c_cflag, | ||
1254 | RELEVANT_IFLAG(tty->termios->c_iflag)); | ||
1255 | |||
1256 | if (old_termios) | ||
1257 | dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, | ||
1258 | old_termios->c_cflag, | ||
1259 | RELEVANT_IFLAG(old_termios->c_iflag)); | ||
1260 | |||
1261 | dbg("%s - port %d", __FUNCTION__, port->number); | ||
1262 | |||
1263 | /* change the port settings to the new ones specified */ | ||
1264 | change_port_settings(mos7720_port, old_termios); | ||
1265 | |||
1266 | if(!port->read_urb) { | ||
1267 | dbg("%s","URB KILLED !!!!!\n"); | ||
1268 | return; | ||
1269 | } | ||
1270 | |||
1271 | if(port->read_urb->status != -EINPROGRESS) { | ||
1272 | port->read_urb->dev = serial->dev; | ||
1273 | status = usb_submit_urb(port->read_urb, GFP_ATOMIC); | ||
1274 | if (status) | ||
1275 | dbg("usb_submit_urb(read bulk) failed, status = %d", | ||
1276 | status); | ||
1277 | } | ||
1278 | return; | ||
1279 | } | ||
1280 | |||
1281 | /* | ||
1282 | * get_lsr_info - get line status register info | ||
1283 | * | ||
1284 | * Purpose: Let user call ioctl() to get info when the UART physically | ||
1285 | * is emptied. On bus types like RS485, the transmitter must | ||
1286 | * release the bus after transmitting. This must be done when | ||
1287 | * the transmit shift register is empty, not be done when the | ||
1288 | * transmit holding register is empty. This functionality | ||
1289 | * allows an RS485 driver to be written in user space. | ||
1290 | */ | ||
1291 | static int get_lsr_info(struct moschip_port *mos7720_port, | ||
1292 | unsigned int __user *value) | ||
1293 | { | ||
1294 | int count; | ||
1295 | unsigned int result = 0; | ||
1296 | |||
1297 | count = mos7720_chars_in_buffer(mos7720_port->port); | ||
1298 | if (count == 0) { | ||
1299 | dbg("%s -- Empty", __FUNCTION__); | ||
1300 | result = TIOCSER_TEMT; | ||
1301 | } | ||
1302 | |||
1303 | if (copy_to_user(value, &result, sizeof(int))) | ||
1304 | return -EFAULT; | ||
1305 | return 0; | ||
1306 | } | ||
1307 | |||
1308 | /* | ||
1309 | * get_number_bytes_avail - get number of bytes available | ||
1310 | * | ||
1311 | * Purpose: Let user call ioctl to get the count of number of bytes available. | ||
1312 | */ | ||
1313 | static int get_number_bytes_avail(struct moschip_port *mos7720_port, | ||
1314 | unsigned int __user *value) | ||
1315 | { | ||
1316 | unsigned int result = 0; | ||
1317 | struct tty_struct *tty = mos7720_port->port->tty; | ||
1318 | |||
1319 | if (!tty) | ||
1320 | return -ENOIOCTLCMD; | ||
1321 | |||
1322 | result = tty->read_cnt; | ||
1323 | |||
1324 | dbg("%s(%d) = %d", __FUNCTION__, mos7720_port->port->number, result); | ||
1325 | if (copy_to_user(value, &result, sizeof(int))) | ||
1326 | return -EFAULT; | ||
1327 | |||
1328 | return -ENOIOCTLCMD; | ||
1329 | } | ||
1330 | |||
1331 | static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, | ||
1332 | unsigned int __user *value) | ||
1333 | { | ||
1334 | unsigned int mcr ; | ||
1335 | unsigned int arg; | ||
1336 | unsigned char data; | ||
1337 | |||
1338 | struct usb_serial_port *port; | ||
1339 | |||
1340 | if (mos7720_port == NULL) | ||
1341 | return -1; | ||
1342 | |||
1343 | port = (struct usb_serial_port*)mos7720_port->port; | ||
1344 | mcr = mos7720_port->shadowMCR; | ||
1345 | |||
1346 | if (copy_from_user(&arg, value, sizeof(int))) | ||
1347 | return -EFAULT; | ||
1348 | |||
1349 | switch (cmd) { | ||
1350 | case TIOCMBIS: | ||
1351 | if (arg & TIOCM_RTS) | ||
1352 | mcr |= UART_MCR_RTS; | ||
1353 | if (arg & TIOCM_DTR) | ||
1354 | mcr |= UART_MCR_RTS; | ||
1355 | if (arg & TIOCM_LOOP) | ||
1356 | mcr |= UART_MCR_LOOP; | ||
1357 | break; | ||
1358 | |||
1359 | case TIOCMBIC: | ||
1360 | if (arg & TIOCM_RTS) | ||
1361 | mcr &= ~UART_MCR_RTS; | ||
1362 | if (arg & TIOCM_DTR) | ||
1363 | mcr &= ~UART_MCR_RTS; | ||
1364 | if (arg & TIOCM_LOOP) | ||
1365 | mcr &= ~UART_MCR_LOOP; | ||
1366 | break; | ||
1367 | |||
1368 | case TIOCMSET: | ||
1369 | /* turn off the RTS and DTR and LOOPBACK | ||
1370 | * and then only turn on what was asked to */ | ||
1371 | mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP); | ||
1372 | mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0); | ||
1373 | mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0); | ||
1374 | mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0); | ||
1375 | break; | ||
1376 | } | ||
1377 | |||
1378 | mos7720_port->shadowMCR = mcr; | ||
1379 | |||
1380 | data = mos7720_port->shadowMCR; | ||
1381 | send_mos_cmd(port->serial, MOS_WRITE, | ||
1382 | port->number - port->serial->minor, UART_MCR, &data); | ||
1383 | |||
1384 | return 0; | ||
1385 | } | ||
1386 | |||
1387 | static int get_modem_info(struct moschip_port *mos7720_port, | ||
1388 | unsigned int __user *value) | ||
1389 | { | ||
1390 | unsigned int result = 0; | ||
1391 | unsigned int msr = mos7720_port->shadowMSR; | ||
1392 | unsigned int mcr = mos7720_port->shadowMCR; | ||
1393 | |||
1394 | result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ | ||
1395 | | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ | ||
1396 | | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ | ||
1397 | | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */ | ||
1398 | | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ | ||
1399 | | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ | ||
1400 | |||
1401 | |||
1402 | dbg("%s -- %x", __FUNCTION__, result); | ||
1403 | |||
1404 | if (copy_to_user(value, &result, sizeof(int))) | ||
1405 | return -EFAULT; | ||
1406 | return 0; | ||
1407 | } | ||
1408 | |||
1409 | static int get_serial_info(struct moschip_port *mos7720_port, | ||
1410 | struct serial_struct __user *retinfo) | ||
1411 | { | ||
1412 | struct serial_struct tmp; | ||
1413 | |||
1414 | if (!retinfo) | ||
1415 | return -EFAULT; | ||
1416 | |||
1417 | memset(&tmp, 0, sizeof(tmp)); | ||
1418 | |||
1419 | tmp.type = PORT_16550A; | ||
1420 | tmp.line = mos7720_port->port->serial->minor; | ||
1421 | tmp.port = mos7720_port->port->number; | ||
1422 | tmp.irq = 0; | ||
1423 | tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; | ||
1424 | tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; | ||
1425 | tmp.baud_base = 9600; | ||
1426 | tmp.close_delay = 5*HZ; | ||
1427 | tmp.closing_wait = 30*HZ; | ||
1428 | |||
1429 | if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) | ||
1430 | return -EFAULT; | ||
1431 | return 0; | ||
1432 | } | ||
1433 | |||
1434 | static int mos7720_ioctl(struct usb_serial_port *port, struct file *file, | ||
1435 | unsigned int cmd, unsigned long arg) | ||
1436 | { | ||
1437 | struct moschip_port *mos7720_port; | ||
1438 | struct async_icount cnow; | ||
1439 | struct async_icount cprev; | ||
1440 | struct serial_icounter_struct icount; | ||
1441 | |||
1442 | mos7720_port = usb_get_serial_port_data(port); | ||
1443 | if (mos7720_port == NULL) | ||
1444 | return -ENODEV; | ||
1445 | |||
1446 | dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); | ||
1447 | |||
1448 | switch (cmd) { | ||
1449 | case TIOCINQ: | ||
1450 | /* return number of bytes available */ | ||
1451 | dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number); | ||
1452 | return get_number_bytes_avail(mos7720_port, | ||
1453 | (unsigned int __user *)arg); | ||
1454 | break; | ||
1455 | |||
1456 | case TIOCSERGETLSR: | ||
1457 | dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); | ||
1458 | return get_lsr_info(mos7720_port, (unsigned int __user *)arg); | ||
1459 | return 0; | ||
1460 | |||
1461 | case TIOCMBIS: | ||
1462 | case TIOCMBIC: | ||
1463 | case TIOCMSET: | ||
1464 | dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, | ||
1465 | port->number); | ||
1466 | return set_modem_info(mos7720_port, cmd, | ||
1467 | (unsigned int __user *)arg); | ||
1468 | |||
1469 | case TIOCMGET: | ||
1470 | dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number); | ||
1471 | return get_modem_info(mos7720_port, | ||
1472 | (unsigned int __user *)arg); | ||
1473 | |||
1474 | case TIOCGSERIAL: | ||
1475 | dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number); | ||
1476 | return get_serial_info(mos7720_port, | ||
1477 | (struct serial_struct __user *)arg); | ||
1478 | |||
1479 | case TIOCSSERIAL: | ||
1480 | dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number); | ||
1481 | break; | ||
1482 | |||
1483 | case TIOCMIWAIT: | ||
1484 | dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); | ||
1485 | cprev = mos7720_port->icount; | ||
1486 | while (1) { | ||
1487 | if (signal_pending(current)) | ||
1488 | return -ERESTARTSYS; | ||
1489 | cnow = mos7720_port->icount; | ||
1490 | if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && | ||
1491 | cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) | ||
1492 | return -EIO; /* no change => error */ | ||
1493 | if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || | ||
1494 | ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || | ||
1495 | ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || | ||
1496 | ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { | ||
1497 | return 0; | ||
1498 | } | ||
1499 | cprev = cnow; | ||
1500 | } | ||
1501 | /* NOTREACHED */ | ||
1502 | break; | ||
1503 | |||
1504 | case TIOCGICOUNT: | ||
1505 | cnow = mos7720_port->icount; | ||
1506 | icount.cts = cnow.cts; | ||
1507 | icount.dsr = cnow.dsr; | ||
1508 | icount.rng = cnow.rng; | ||
1509 | icount.dcd = cnow.dcd; | ||
1510 | icount.rx = cnow.rx; | ||
1511 | icount.tx = cnow.tx; | ||
1512 | icount.frame = cnow.frame; | ||
1513 | icount.overrun = cnow.overrun; | ||
1514 | icount.parity = cnow.parity; | ||
1515 | icount.brk = cnow.brk; | ||
1516 | icount.buf_overrun = cnow.buf_overrun; | ||
1517 | |||
1518 | dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, | ||
1519 | port->number, icount.rx, icount.tx ); | ||
1520 | if (copy_to_user((void __user *)arg, &icount, sizeof(icount))) | ||
1521 | return -EFAULT; | ||
1522 | return 0; | ||
1523 | } | ||
1524 | |||
1525 | return -ENOIOCTLCMD; | ||
1526 | } | ||
1527 | |||
1528 | static int mos7720_startup(struct usb_serial *serial) | ||
1529 | { | ||
1530 | struct moschip_serial *mos7720_serial; | ||
1531 | struct moschip_port *mos7720_port; | ||
1532 | struct usb_device *dev; | ||
1533 | int i; | ||
1534 | char data; | ||
1535 | |||
1536 | dbg("%s: Entering ..........", __FUNCTION__); | ||
1537 | |||
1538 | if (!serial) { | ||
1539 | dbg("Invalid Handler"); | ||
1540 | return -ENODEV; | ||
1541 | } | ||
1542 | |||
1543 | dev = serial->dev; | ||
1544 | |||
1545 | /* create our private serial structure */ | ||
1546 | mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL); | ||
1547 | if (mos7720_serial == NULL) { | ||
1548 | err("%s - Out of memory", __FUNCTION__); | ||
1549 | return -ENOMEM; | ||
1550 | } | ||
1551 | |||
1552 | usb_set_serial_data(serial, mos7720_serial); | ||
1553 | |||
1554 | /* we set up the pointers to the endpoints in the mos7720_open * | ||
1555 | * function, as the structures aren't created yet. */ | ||
1556 | |||
1557 | /* set up port private structures */ | ||
1558 | for (i = 0; i < serial->num_ports; ++i) { | ||
1559 | mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); | ||
1560 | if (mos7720_port == NULL) { | ||
1561 | err("%s - Out of memory", __FUNCTION__); | ||
1562 | usb_set_serial_data(serial, NULL); | ||
1563 | kfree(mos7720_serial); | ||
1564 | return -ENOMEM; | ||
1565 | } | ||
1566 | |||
1567 | /* Initialize all port interrupt end point to port 0 int | ||
1568 | * endpoint. Our device has only one interrupt endpoint | ||
1569 | * comman to all ports */ | ||
1570 | serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress; | ||
1571 | |||
1572 | mos7720_port->port = serial->port[i]; | ||
1573 | usb_set_serial_port_data(serial->port[i], mos7720_port); | ||
1574 | |||
1575 | dbg("port number is %d", serial->port[i]->number); | ||
1576 | dbg("serial number is %d", serial->minor); | ||
1577 | } | ||
1578 | |||
1579 | |||
1580 | /* setting configuration feature to one */ | ||
1581 | usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), | ||
1582 | (__u8)0x03, 0x00,0x01,0x00, NULL, 0x00, 5*HZ); | ||
1583 | |||
1584 | send_mos_cmd(serial,MOS_READ,0x00, UART_LSR, &data); // LSR For Port 1 | ||
1585 | dbg("LSR:%x",data); | ||
1586 | |||
1587 | send_mos_cmd(serial,MOS_READ,0x01, UART_LSR, &data); // LSR For Port 2 | ||
1588 | dbg("LSR:%x",data); | ||
1589 | |||
1590 | return 0; | ||
1591 | } | ||
1592 | |||
1593 | static void mos7720_shutdown(struct usb_serial *serial) | ||
1594 | { | ||
1595 | int i; | ||
1596 | |||
1597 | /* free private structure allocated for serial port */ | ||
1598 | for (i=0; i < serial->num_ports; ++i) { | ||
1599 | kfree(usb_get_serial_port_data(serial->port[i])); | ||
1600 | usb_set_serial_port_data(serial->port[i], NULL); | ||
1601 | } | ||
1602 | |||
1603 | /* free private structure allocated for serial device */ | ||
1604 | kfree(usb_get_serial_data(serial)); | ||
1605 | usb_set_serial_data(serial, NULL); | ||
1606 | } | ||
1607 | |||
1608 | static struct usb_serial_driver moschip7720_2port_driver = { | ||
1609 | .driver = { | ||
1610 | .owner = THIS_MODULE, | ||
1611 | .name = "moschip7720", | ||
1612 | }, | ||
1613 | .description = "Moschip 2 port adapter", | ||
1614 | .id_table = moschip_port_id_table, | ||
1615 | .num_interrupt_in = 1, | ||
1616 | .num_bulk_in = 2, | ||
1617 | .num_bulk_out = 2, | ||
1618 | .num_ports = 2, | ||
1619 | .open = mos7720_open, | ||
1620 | .close = mos7720_close, | ||
1621 | .throttle = mos7720_throttle, | ||
1622 | .unthrottle = mos7720_unthrottle, | ||
1623 | .attach = mos7720_startup, | ||
1624 | .shutdown = mos7720_shutdown, | ||
1625 | .ioctl = mos7720_ioctl, | ||
1626 | .set_termios = mos7720_set_termios, | ||
1627 | .write = mos7720_write, | ||
1628 | .write_room = mos7720_write_room, | ||
1629 | .chars_in_buffer = mos7720_chars_in_buffer, | ||
1630 | .break_ctl = mos7720_break, | ||
1631 | .read_bulk_callback = mos7720_bulk_in_callback, | ||
1632 | }; | ||
1633 | |||
1634 | static struct usb_driver usb_driver = { | ||
1635 | .name = "moschip7720", | ||
1636 | .probe = usb_serial_probe, | ||
1637 | .disconnect = usb_serial_disconnect, | ||
1638 | .id_table = moschip_port_id_table, | ||
1639 | }; | ||
1640 | |||
1641 | static int __init moschip7720_init(void) | ||
1642 | { | ||
1643 | int retval; | ||
1644 | |||
1645 | dbg("%s: Entering ..........", __FUNCTION__); | ||
1646 | |||
1647 | /* Register with the usb serial */ | ||
1648 | retval = usb_serial_register(&moschip7720_2port_driver); | ||
1649 | if (retval) | ||
1650 | goto failed_port_device_register; | ||
1651 | |||
1652 | info(DRIVER_DESC " " DRIVER_VERSION); | ||
1653 | |||
1654 | /* Register with the usb */ | ||
1655 | retval = usb_register(&usb_driver); | ||
1656 | if (retval) | ||
1657 | goto failed_usb_register; | ||
1658 | |||
1659 | return 0; | ||
1660 | |||
1661 | failed_usb_register: | ||
1662 | usb_serial_deregister(&moschip7720_2port_driver); | ||
1663 | |||
1664 | failed_port_device_register: | ||
1665 | return retval; | ||
1666 | } | ||
1667 | |||
1668 | static void __exit moschip7720_exit(void) | ||
1669 | { | ||
1670 | usb_deregister(&usb_driver); | ||
1671 | usb_serial_deregister(&moschip7720_2port_driver); | ||
1672 | } | ||
1673 | |||
1674 | module_init(moschip7720_init); | ||
1675 | module_exit(moschip7720_exit); | ||
1676 | |||
1677 | /* Module information */ | ||
1678 | MODULE_AUTHOR( DRIVER_AUTHOR ); | ||
1679 | MODULE_DESCRIPTION( DRIVER_DESC ); | ||
1680 | MODULE_LICENSE("GPL"); | ||
1681 | |||
1682 | module_param(debug, bool, S_IRUGO | S_IWUSR); | ||
1683 | MODULE_PARM_DESC(debug, "Debug enabled or not"); | ||