blob: f9832b72c010ba172d3ab226c34ccb5a5d13bbfd [file] [log] [blame]
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001/*
2 * Infinity Unlimited USB Phoenix driver
3 *
James Courtier-Dutton89b54392010-05-21 11:53:25 +01004 * Copyright (C) 2010 James Courtier-Dutton (James@superbug.co.uk)
5
Alain Degreffe60a8fc02007-10-26 13:51:49 +02006 * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com)
7 *
8 * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás)
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * And tested with help of WB Electronics
16 *
17 */
18#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>
29#include <linux/uaccess.h>
30#include <linux/usb.h>
31#include <linux/usb/serial.h>
32#include "iuu_phoenix.h"
33#include <linux/random.h>
34
35
36#ifdef CONFIG_USB_SERIAL_DEBUG
Rusty Russell90ab5ee2012-01-13 09:32:20 +103037static bool debug = 1;
Alain Degreffe60a8fc02007-10-26 13:51:49 +020038#else
Rusty Russell90ab5ee2012-01-13 09:32:20 +103039static bool debug;
Alain Degreffe60a8fc02007-10-26 13:51:49 +020040#endif
41
42/*
43 * Version Information
44 */
James Courtier-Dutton89b54392010-05-21 11:53:25 +010045#define DRIVER_VERSION "v0.12"
Alain Degreffe60a8fc02007-10-26 13:51:49 +020046#define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
47
Németh Márton7d40d7e2010-01-10 15:34:24 +010048static const struct usb_device_id id_table[] = {
Alain Degreffe60a8fc02007-10-26 13:51:49 +020049 {USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)},
50 {} /* Terminating entry */
51};
52MODULE_DEVICE_TABLE(usb, id_table);
53
Alain Degreffe60a8fc02007-10-26 13:51:49 +020054/* turbo parameter */
55static int boost = 100;
56static int clockmode = 1;
57static int cdmode = 1;
58static int iuu_cardin;
59static int iuu_cardout;
Rusty Russell90ab5ee2012-01-13 09:32:20 +103060static bool xmas;
Olivier Bornete55c6d02009-08-18 21:05:57 +020061static int vcc_default = 5;
Alain Degreffe60a8fc02007-10-26 13:51:49 +020062
63static void read_rxcmd_callback(struct urb *urb);
64
65struct iuu_private {
66 spinlock_t lock; /* store irq state */
67 wait_queue_head_t delta_msr_wait;
Alain Degreffe60a8fc02007-10-26 13:51:49 +020068 u8 line_status;
Alain Degreffe60a8fc02007-10-26 13:51:49 +020069 int tiostatus; /* store IUART SIGNAL for tiocmget call */
70 u8 reset; /* if 1 reset is needed */
71 int poll; /* number of poll */
72 u8 *writebuf; /* buffer for writing to device */
73 int writelen; /* num of byte to write to device */
74 u8 *buf; /* used for initialize speed */
Alain Degreffe60a8fc02007-10-26 13:51:49 +020075 u8 len;
Olivier Bornet20eda942009-08-18 21:05:55 +020076 int vcc; /* vcc (either 3 or 5 V) */
James Courtier-Dutton89b54392010-05-21 11:53:25 +010077 u32 baud;
78 u32 boost;
79 u32 clk;
Alain Degreffe60a8fc02007-10-26 13:51:49 +020080};
81
82
83static void iuu_free_buf(struct iuu_private *priv)
84{
85 kfree(priv->buf);
Alain Degreffe60a8fc02007-10-26 13:51:49 +020086 kfree(priv->writebuf);
87}
88
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -070089static int iuu_alloc_buf(struct usb_serial *serial, struct iuu_private *priv)
Alain Degreffe60a8fc02007-10-26 13:51:49 +020090{
91 priv->buf = kzalloc(256, GFP_KERNEL);
Alain Degreffe60a8fc02007-10-26 13:51:49 +020092 priv->writebuf = kzalloc(256, GFP_KERNEL);
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -070093 if (!priv->buf || !priv->writebuf) {
Alain Degreffe60a8fc02007-10-26 13:51:49 +020094 iuu_free_buf(priv);
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -070095 dev_dbg(&serial->dev->dev, "%s problem allocation buffer\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +020096 return -ENOMEM;
97 }
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -070098 dev_dbg(&serial->dev->dev, "%s - Privates buffers allocation success\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +020099 return 0;
100}
101
102static int iuu_startup(struct usb_serial *serial)
103{
104 struct iuu_private *priv;
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700105
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200106 priv = kzalloc(sizeof(struct iuu_private), GFP_KERNEL);
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700107 dev_dbg(&serial->dev->dev, "%s- priv allocation success\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200108 if (!priv)
109 return -ENOMEM;
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700110 if (iuu_alloc_buf(serial, priv)) {
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200111 kfree(priv);
112 return -ENOMEM;
113 }
Olivier Bornete55c6d02009-08-18 21:05:57 +0200114 priv->vcc = vcc_default;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200115 spin_lock_init(&priv->lock);
116 init_waitqueue_head(&priv->delta_msr_wait);
117 usb_set_serial_port_data(serial->port[0], priv);
118 return 0;
119}
120
Alan Sternf9c99bb2009-06-02 11:53:55 -0400121/* Release function */
122static void iuu_release(struct usb_serial *serial)
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200123{
124 struct usb_serial_port *port = serial->port[0];
125 struct iuu_private *priv = usb_get_serial_port_data(port);
126 if (!port)
127 return;
128
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200129 if (priv) {
130 iuu_free_buf(priv);
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700131 dev_dbg(&port->dev, "%s - I will free all\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200132 usb_set_serial_port_data(port, NULL);
133
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700134 dev_dbg(&port->dev, "%s - priv is not anymore in port structure\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200135 kfree(priv);
136
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700137 dev_dbg(&port->dev, "%s priv is now kfree\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200138 }
139}
140
Alan Cox20b9d172011-02-14 16:26:50 +0000141static int iuu_tiocmset(struct tty_struct *tty,
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200142 unsigned int set, unsigned int clear)
143{
Alan Cox95da3102008-07-22 11:09:07 +0100144 struct usb_serial_port *port = tty->driver_data;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200145 struct iuu_private *priv = usb_get_serial_port_data(port);
Alan Cox7b1fc8b2008-02-20 21:39:25 +0000146 unsigned long flags;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200147
Alan Cox7b1fc8b2008-02-20 21:39:25 +0000148 /* FIXME: locking on tiomstatus */
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700149 dev_dbg(&port->dev, "%s msg : SET = 0x%04x, CLEAR = 0x%04x\n",
150 __func__, set, clear);
Alan Cox7b1fc8b2008-02-20 21:39:25 +0000151
152 spin_lock_irqsave(&priv->lock, flags);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200153
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100154 if ((set & TIOCM_RTS) && !(priv->tiostatus == TIOCM_RTS)) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700155 dev_dbg(&port->dev, "%s TIOCMSET RESET called !!!\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200156 priv->reset = 1;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200157 }
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100158 if (set & TIOCM_RTS)
159 priv->tiostatus = TIOCM_RTS;
160
Alan Cox7b1fc8b2008-02-20 21:39:25 +0000161 spin_unlock_irqrestore(&priv->lock, flags);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200162 return 0;
163}
164
165/* This is used to provide a carrier detect mechanism
166 * When a card is present, the response is 0x00
167 * When no card , the reader respond with TIOCM_CD
168 * This is known as CD autodetect mechanism
169 */
Alan Cox60b33c12011-02-14 16:26:14 +0000170static int iuu_tiocmget(struct tty_struct *tty)
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200171{
Alan Cox95da3102008-07-22 11:09:07 +0100172 struct usb_serial_port *port = tty->driver_data;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200173 struct iuu_private *priv = usb_get_serial_port_data(port);
Alan Cox7b1fc8b2008-02-20 21:39:25 +0000174 unsigned long flags;
175 int rc;
176
177 spin_lock_irqsave(&priv->lock, flags);
178 rc = priv->tiostatus;
179 spin_unlock_irqrestore(&priv->lock, flags);
180
181 return rc;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200182}
183
184static void iuu_rxcmd(struct urb *urb)
185{
Ming Leicdc97792008-02-24 18:41:47 +0800186 struct usb_serial_port *port = urb->context;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200187 int result;
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800188 int status = urb->status;
189
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800190 if (status) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700191 dev_dbg(&port->dev, "%s - status = %d\n", __func__, status);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200192 /* error stop all */
193 return;
194 }
195
196
197 memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
198 usb_fill_bulk_urb(port->write_urb, port->serial->dev,
199 usb_sndbulkpipe(port->serial->dev,
200 port->bulk_out_endpointAddress),
201 port->write_urb->transfer_buffer, 1,
202 read_rxcmd_callback, port);
203 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
204}
205
206static int iuu_reset(struct usb_serial_port *port, u8 wt)
207{
208 struct iuu_private *priv = usb_get_serial_port_data(port);
209 int result;
210 char *buf_ptr = port->write_urb->transfer_buffer;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200211
212 /* Prepare the reset sequence */
213
214 *buf_ptr++ = IUU_RST_SET;
215 *buf_ptr++ = IUU_DELAY_MS;
216 *buf_ptr++ = wt;
217 *buf_ptr = IUU_RST_CLEAR;
218
219 /* send the sequence */
220
221 usb_fill_bulk_urb(port->write_urb,
222 port->serial->dev,
223 usb_sndbulkpipe(port->serial->dev,
224 port->bulk_out_endpointAddress),
225 port->write_urb->transfer_buffer, 4, iuu_rxcmd, port);
226 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
227 priv->reset = 0;
228 return result;
229}
230
231/* Status Function
232 * Return value is
233 * 0x00 = no card
234 * 0x01 = smartcard
235 * 0x02 = sim card
236 */
237static void iuu_update_status_callback(struct urb *urb)
238{
Ming Leicdc97792008-02-24 18:41:47 +0800239 struct usb_serial_port *port = urb->context;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200240 struct iuu_private *priv = usb_get_serial_port_data(port);
241 u8 *st;
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800242 int status = urb->status;
243
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800244 if (status) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700245 dev_dbg(&port->dev, "%s - status = %d\n", __func__, status);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200246 /* error stop all */
247 return;
248 }
249
250 st = urb->transfer_buffer;
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700251 dev_dbg(&port->dev, "%s - enter\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200252 if (urb->actual_length == 1) {
253 switch (st[0]) {
254 case 0x1:
255 priv->tiostatus = iuu_cardout;
256 break;
257 case 0x0:
258 priv->tiostatus = iuu_cardin;
259 break;
260 default:
261 priv->tiostatus = iuu_cardin;
262 }
263 }
264 iuu_rxcmd(urb);
265}
266
267static void iuu_status_callback(struct urb *urb)
268{
Ming Leicdc97792008-02-24 18:41:47 +0800269 struct usb_serial_port *port = urb->context;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200270 int result;
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800271 int status = urb->status;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200272
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700273 dev_dbg(&port->dev, "%s - status = %d\n", __func__, status);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200274 usb_fill_bulk_urb(port->read_urb, port->serial->dev,
275 usb_rcvbulkpipe(port->serial->dev,
276 port->bulk_in_endpointAddress),
277 port->read_urb->transfer_buffer, 256,
278 iuu_update_status_callback, port);
279 result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
280}
281
282static int iuu_status(struct usb_serial_port *port)
283{
284 int result;
285
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200286 memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1);
287 usb_fill_bulk_urb(port->write_urb, port->serial->dev,
288 usb_sndbulkpipe(port->serial->dev,
289 port->bulk_out_endpointAddress),
290 port->write_urb->transfer_buffer, 1,
291 iuu_status_callback, port);
292 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
293 return result;
294
295}
296
297static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
298{
299 int status;
300 struct usb_serial *serial = port->serial;
301 int actual = 0;
302
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200303 /* send the data out the bulk port */
304
305 status =
306 usb_bulk_msg(serial->dev,
307 usb_sndbulkpipe(serial->dev,
308 port->bulk_out_endpointAddress), buf,
309 count, &actual, HZ * 1);
310
Alan Cox9e8e2d22008-07-22 11:12:59 +0100311 if (status != IUU_OPERATION_OK)
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700312 dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status);
Alan Cox9e8e2d22008-07-22 11:12:59 +0100313 else
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700314 dev_dbg(&port->dev, "%s - write OK !\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200315 return status;
316}
317
318static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count)
319{
320 int status;
321 struct usb_serial *serial = port->serial;
322 int actual = 0;
323
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200324 /* send the data out the bulk port */
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200325 status =
326 usb_bulk_msg(serial->dev,
327 usb_rcvbulkpipe(serial->dev,
328 port->bulk_in_endpointAddress), buf,
329 count, &actual, HZ * 1);
330
Alan Cox9e8e2d22008-07-22 11:12:59 +0100331 if (status != IUU_OPERATION_OK)
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700332 dev_dbg(&port->dev, "%s - error = %2x\n", __func__, status);
Alan Cox9e8e2d22008-07-22 11:12:59 +0100333 else
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700334 dev_dbg(&port->dev, "%s - read OK !\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200335 return status;
336}
337
338static int iuu_led(struct usb_serial_port *port, unsigned int R,
339 unsigned int G, unsigned int B, u8 f)
340{
341 int status;
342 u8 *buf;
343 buf = kmalloc(8, GFP_KERNEL);
344 if (!buf)
345 return -ENOMEM;
346
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200347 buf[0] = IUU_SET_LED;
348 buf[1] = R & 0xFF;
349 buf[2] = (R >> 8) & 0xFF;
350 buf[3] = G & 0xFF;
351 buf[4] = (G >> 8) & 0xFF;
352 buf[5] = B & 0xFF;
353 buf[6] = (B >> 8) & 0xFF;
354 buf[7] = f;
355 status = bulk_immediate(port, buf, 8);
356 kfree(buf);
357 if (status != IUU_OPERATION_OK)
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700358 dev_dbg(&port->dev, "%s - led error status = %2x\n", __func__, status);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200359 else
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700360 dev_dbg(&port->dev, "%s - led OK !\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200361 return IUU_OPERATION_OK;
362}
363
364static void iuu_rgbf_fill_buffer(u8 *buf, u8 r1, u8 r2, u8 g1, u8 g2, u8 b1,
365 u8 b2, u8 freq)
366{
367 *buf++ = IUU_SET_LED;
368 *buf++ = r1;
369 *buf++ = r2;
370 *buf++ = g1;
371 *buf++ = g2;
372 *buf++ = b1;
373 *buf++ = b2;
374 *buf = freq;
375}
376
377static void iuu_led_activity_on(struct urb *urb)
378{
Ming Leicdc97792008-02-24 18:41:47 +0800379 struct usb_serial_port *port = urb->context;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200380 int result;
381 char *buf_ptr = port->write_urb->transfer_buffer;
382 *buf_ptr++ = IUU_SET_LED;
383 if (xmas == 1) {
384 get_random_bytes(buf_ptr, 6);
385 *(buf_ptr+7) = 1;
386 } else {
387 iuu_rgbf_fill_buffer(buf_ptr, 255, 255, 0, 0, 0, 0, 255);
388 }
389
390 usb_fill_bulk_urb(port->write_urb, port->serial->dev,
391 usb_sndbulkpipe(port->serial->dev,
392 port->bulk_out_endpointAddress),
393 port->write_urb->transfer_buffer, 8 ,
394 iuu_rxcmd, port);
395 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
396}
397
398static void iuu_led_activity_off(struct urb *urb)
399{
Ming Leicdc97792008-02-24 18:41:47 +0800400 struct usb_serial_port *port = urb->context;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200401 int result;
402 char *buf_ptr = port->write_urb->transfer_buffer;
403 if (xmas == 1) {
404 iuu_rxcmd(urb);
405 return;
406 } else {
407 *buf_ptr++ = IUU_SET_LED;
408 iuu_rgbf_fill_buffer(buf_ptr, 0, 0, 255, 255, 0, 0, 255);
409 }
410 usb_fill_bulk_urb(port->write_urb, port->serial->dev,
411 usb_sndbulkpipe(port->serial->dev,
412 port->bulk_out_endpointAddress),
413 port->write_urb->transfer_buffer, 8 ,
414 iuu_rxcmd, port);
415 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
416}
417
418
419
420static int iuu_clk(struct usb_serial_port *port, int dwFrq)
421{
422 int status;
423 struct iuu_private *priv = usb_get_serial_port_data(port);
424 int Count = 0;
425 u8 FrqGenAdr = 0x69;
426 u8 DIV = 0; /* 8bit */
427 u8 XDRV = 0; /* 8bit */
428 u8 PUMP = 0; /* 3bit */
429 u8 PBmsb = 0; /* 2bit */
430 u8 PBlsb = 0; /* 8bit */
431 u8 PO = 0; /* 1bit */
432 u8 Q = 0; /* 7bit */
433 /* 24bit = 3bytes */
434 unsigned int P = 0;
435 unsigned int P2 = 0;
436 int frq = (int)dwFrq;
437
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200438 if (frq == 0) {
439 priv->buf[Count++] = IUU_UART_WRITE_I2C;
440 priv->buf[Count++] = FrqGenAdr << 1;
441 priv->buf[Count++] = 0x09;
442 priv->buf[Count++] = 0x00;
443
444 status = bulk_immediate(port, (u8 *) priv->buf, Count);
445 if (status != 0) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700446 dev_dbg(&port->dev, "%s - write error\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200447 return status;
448 }
449 } else if (frq == 3579000) {
450 DIV = 100;
451 P = 1193;
452 Q = 40;
453 XDRV = 0;
454 } else if (frq == 3680000) {
455 DIV = 105;
456 P = 161;
457 Q = 5;
458 XDRV = 0;
459 } else if (frq == 6000000) {
460 DIV = 66;
461 P = 66;
462 Q = 2;
463 XDRV = 0x28;
464 } else {
465 unsigned int result = 0;
466 unsigned int tmp = 0;
467 unsigned int check;
468 unsigned int check2;
469 char found = 0x00;
470 unsigned int lQ = 2;
471 unsigned int lP = 2055;
472 unsigned int lDiv = 4;
473
474 for (lQ = 2; lQ <= 47 && !found; lQ++)
475 for (lP = 2055; lP >= 8 && !found; lP--)
476 for (lDiv = 4; lDiv <= 127 && !found; lDiv++) {
477 tmp = (12000000 / lDiv) * (lP / lQ);
478 if (abs((int)(tmp - frq)) <
479 abs((int)(frq - result))) {
480 check2 = (12000000 / lQ);
481 if (check2 < 250000)
482 continue;
483 check = (12000000 / lQ) * lP;
484 if (check > 400000000)
485 continue;
486 if (check < 100000000)
487 continue;
488 if (lDiv < 4 || lDiv > 127)
489 continue;
490 result = tmp;
491 P = lP;
492 DIV = lDiv;
493 Q = lQ;
494 if (result == frq)
495 found = 0x01;
496 }
497 }
498 }
499 P2 = ((P - PO) / 2) - 4;
500 DIV = DIV;
501 PUMP = 0x04;
502 PBmsb = (P2 >> 8 & 0x03);
503 PBlsb = P2 & 0xFF;
504 PO = (P >> 10) & 0x01;
505 Q = Q - 2;
506
507 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
508 priv->buf[Count++] = FrqGenAdr << 1;
509 priv->buf[Count++] = 0x09;
510 priv->buf[Count++] = 0x20; /* Adr = 0x09 */
511 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
512 priv->buf[Count++] = FrqGenAdr << 1;
513 priv->buf[Count++] = 0x0C;
514 priv->buf[Count++] = DIV; /* Adr = 0x0C */
515 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
516 priv->buf[Count++] = FrqGenAdr << 1;
517 priv->buf[Count++] = 0x12;
518 priv->buf[Count++] = XDRV; /* Adr = 0x12 */
519 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
520 priv->buf[Count++] = FrqGenAdr << 1;
521 priv->buf[Count++] = 0x13;
522 priv->buf[Count++] = 0x6B; /* Adr = 0x13 */
523 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
524 priv->buf[Count++] = FrqGenAdr << 1;
525 priv->buf[Count++] = 0x40;
526 priv->buf[Count++] = (0xC0 | ((PUMP & 0x07) << 2)) |
527 (PBmsb & 0x03); /* Adr = 0x40 */
528 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
529 priv->buf[Count++] = FrqGenAdr << 1;
530 priv->buf[Count++] = 0x41;
531 priv->buf[Count++] = PBlsb; /* Adr = 0x41 */
532 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
533 priv->buf[Count++] = FrqGenAdr << 1;
534 priv->buf[Count++] = 0x42;
535 priv->buf[Count++] = Q | (((PO & 0x01) << 7)); /* Adr = 0x42 */
536 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
537 priv->buf[Count++] = FrqGenAdr << 1;
538 priv->buf[Count++] = 0x44;
539 priv->buf[Count++] = (char)0xFF; /* Adr = 0x44 */
540 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
541 priv->buf[Count++] = FrqGenAdr << 1;
542 priv->buf[Count++] = 0x45;
543 priv->buf[Count++] = (char)0xFE; /* Adr = 0x45 */
544 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
545 priv->buf[Count++] = FrqGenAdr << 1;
546 priv->buf[Count++] = 0x46;
547 priv->buf[Count++] = 0x7F; /* Adr = 0x46 */
548 priv->buf[Count++] = IUU_UART_WRITE_I2C; /* 0x4C */
549 priv->buf[Count++] = FrqGenAdr << 1;
550 priv->buf[Count++] = 0x47;
551 priv->buf[Count++] = (char)0x84; /* Adr = 0x47 */
552
553 status = bulk_immediate(port, (u8 *) priv->buf, Count);
554 if (status != IUU_OPERATION_OK)
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700555 dev_dbg(&port->dev, "%s - write error\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200556 return status;
557}
558
559static int iuu_uart_flush(struct usb_serial_port *port)
560{
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700561 struct device *dev = &port->dev;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200562 int i;
563 int status;
564 u8 rxcmd = IUU_UART_RX;
565 struct iuu_private *priv = usb_get_serial_port_data(port);
566
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200567 if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0)
568 return -EIO;
569
570 for (i = 0; i < 2; i++) {
571 status = bulk_immediate(port, &rxcmd, 1);
572 if (status != IUU_OPERATION_OK) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700573 dev_dbg(dev, "%s - uart_flush_write error\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200574 return status;
575 }
576
577 status = read_immediate(port, &priv->len, 1);
578 if (status != IUU_OPERATION_OK) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700579 dev_dbg(dev, "%s - uart_flush_read error\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200580 return status;
581 }
582
583 if (priv->len > 0) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700584 dev_dbg(dev, "%s - uart_flush datalen is : %i\n", __func__, priv->len);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200585 status = read_immediate(port, priv->buf, priv->len);
586 if (status != IUU_OPERATION_OK) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700587 dev_dbg(dev, "%s - uart_flush_read error\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200588 return status;
589 }
590 }
591 }
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700592 dev_dbg(dev, "%s - uart_flush_read OK!\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200593 iuu_led(port, 0, 0xF000, 0, 0xFF);
594 return status;
595}
596
597static void read_buf_callback(struct urb *urb)
598{
Ming Leicdc97792008-02-24 18:41:47 +0800599 struct usb_serial_port *port = urb->context;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200600 unsigned char *data = urb->transfer_buffer;
601 struct tty_struct *tty;
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800602 int status = urb->status;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200603
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800604 if (status) {
605 if (status == -EPROTO) {
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200606 /* reschedule needed */
607 }
608 return;
609 }
610
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700611 dev_dbg(&port->dev, "%s - %i chars to write\n", __func__, urb->actual_length);
Alan Cox4a90f092008-10-13 10:39:46 +0100612 tty = tty_port_tty_get(&port->port);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200613 if (data == NULL)
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700614 dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200615 if (tty && urb->actual_length && data) {
616 tty_insert_flip_string(tty, data, urb->actual_length);
617 tty_flip_buffer_push(tty);
618 }
Alan Cox4a90f092008-10-13 10:39:46 +0100619 tty_kref_put(tty);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200620 iuu_led_activity_on(urb);
621}
622
623static int iuu_bulk_write(struct usb_serial_port *port)
624{
625 struct iuu_private *priv = usb_get_serial_port_data(port);
Steven Rostedt85943032008-05-06 20:42:31 -0700626 unsigned long flags;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200627 int result;
Olivier Bornet5fcf62b2009-06-11 12:52:26 +0100628 int buf_len;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200629 char *buf_ptr = port->write_urb->transfer_buffer;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200630
Olivier Bornet5fcf62b2009-06-11 12:52:26 +0100631 spin_lock_irqsave(&priv->lock, flags);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200632 *buf_ptr++ = IUU_UART_ESC;
633 *buf_ptr++ = IUU_UART_TX;
634 *buf_ptr++ = priv->writelen;
635
Olivier Bornet5fcf62b2009-06-11 12:52:26 +0100636 memcpy(buf_ptr, priv->writebuf, priv->writelen);
637 buf_len = priv->writelen;
638 priv->writelen = 0;
639 spin_unlock_irqrestore(&priv->lock, flags);
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700640 dev_dbg(&port->dev, "%s - writing %i chars : %*ph\n", __func__,
641 buf_len, buf_len, buf_ptr);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200642 usb_fill_bulk_urb(port->write_urb, port->serial->dev,
643 usb_sndbulkpipe(port->serial->dev,
644 port->bulk_out_endpointAddress),
Olivier Bornet5fcf62b2009-06-11 12:52:26 +0100645 port->write_urb->transfer_buffer, buf_len + 3,
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200646 iuu_rxcmd, port);
647 result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200648 usb_serial_port_softint(port);
649 return result;
650}
651
652static int iuu_read_buf(struct usb_serial_port *port, int len)
653{
654 int result;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200655
656 usb_fill_bulk_urb(port->read_urb, port->serial->dev,
657 usb_rcvbulkpipe(port->serial->dev,
658 port->bulk_in_endpointAddress),
659 port->read_urb->transfer_buffer, len,
660 read_buf_callback, port);
661 result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
662 return result;
663}
664
665static void iuu_uart_read_callback(struct urb *urb)
666{
Ming Leicdc97792008-02-24 18:41:47 +0800667 struct usb_serial_port *port = urb->context;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200668 struct iuu_private *priv = usb_get_serial_port_data(port);
Steven Rostedt85943032008-05-06 20:42:31 -0700669 unsigned long flags;
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800670 int status = urb->status;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200671 int error = 0;
672 int len = 0;
673 unsigned char *data = urb->transfer_buffer;
674 priv->poll++;
675
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800676 if (status) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700677 dev_dbg(&port->dev, "%s - status = %d\n", __func__, status);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200678 /* error stop all */
679 return;
680 }
681 if (data == NULL)
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700682 dev_dbg(&port->dev, "%s - data is NULL !!!\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200683
684 if (urb->actual_length == 1 && data != NULL)
685 len = (int) data[0];
686
687 if (urb->actual_length > 1) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700688 dev_dbg(&port->dev, "%s - urb->actual_length = %i\n", __func__,
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200689 urb->actual_length);
690 error = 1;
691 return;
692 }
693 /* if len > 0 call readbuf */
694
695 if (len > 0 && error == 0) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700696 dev_dbg(&port->dev, "%s - call read buf - len to read is %i\n",
Harvey Harrison441b62c2008-03-03 16:08:34 -0800697 __func__, len);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200698 status = iuu_read_buf(port, len);
699 return;
700 }
701 /* need to update status ? */
702 if (priv->poll > 99) {
703 status = iuu_status(port);
704 priv->poll = 0;
705 return;
706 }
707
708 /* reset waiting ? */
709
710 if (priv->reset == 1) {
711 status = iuu_reset(port, 0xC);
712 return;
713 }
714 /* Writebuf is waiting */
715 spin_lock_irqsave(&priv->lock, flags);
716 if (priv->writelen > 0) {
717 spin_unlock_irqrestore(&priv->lock, flags);
718 status = iuu_bulk_write(port);
719 return;
720 }
721 spin_unlock_irqrestore(&priv->lock, flags);
722 /* if nothing to write call again rxcmd */
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700723 dev_dbg(&port->dev, "%s - rxcmd recall\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200724 iuu_led_activity_off(urb);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200725}
726
Alan Cox95da3102008-07-22 11:09:07 +0100727static int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port,
728 const u8 *buf, int count)
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200729{
730 struct iuu_private *priv = usb_get_serial_port_data(port);
Steven Rostedt85943032008-05-06 20:42:31 -0700731 unsigned long flags;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200732
733 if (count > 256)
734 return -ENOMEM;
735
736 spin_lock_irqsave(&priv->lock, flags);
Olivier Bornet5fcf62b2009-06-11 12:52:26 +0100737
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200738 /* fill the buffer */
Olivier Bornet5fcf62b2009-06-11 12:52:26 +0100739 memcpy(priv->writebuf + priv->writelen, buf, count);
740 priv->writelen += count;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200741 spin_unlock_irqrestore(&priv->lock, flags);
742
Alan Cox9e8e2d22008-07-22 11:12:59 +0100743 return count;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200744}
745
746static void read_rxcmd_callback(struct urb *urb)
747{
Ming Leicdc97792008-02-24 18:41:47 +0800748 struct usb_serial_port *port = urb->context;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200749 int result;
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800750 int status = urb->status;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200751
Greg Kroah-Hartman50de36f2008-12-10 16:00:30 -0800752 if (status) {
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200753 /* error stop all */
754 return;
755 }
756
757 usb_fill_bulk_urb(port->read_urb, port->serial->dev,
758 usb_rcvbulkpipe(port->serial->dev,
759 port->bulk_in_endpointAddress),
760 port->read_urb->transfer_buffer, 256,
761 iuu_uart_read_callback, port);
762 result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700763 dev_dbg(&port->dev, "%s - submit result = %d\n", __func__, result);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200764}
765
766static int iuu_uart_on(struct usb_serial_port *port)
767{
768 int status;
769 u8 *buf;
770
771 buf = kmalloc(sizeof(u8) * 4, GFP_KERNEL);
772
773 if (!buf)
774 return -ENOMEM;
775
776 buf[0] = IUU_UART_ENABLE;
777 buf[1] = (u8) ((IUU_BAUD_9600 >> 8) & 0x00FF);
778 buf[2] = (u8) (0x00FF & IUU_BAUD_9600);
Olivier Bornetcc3447d2009-06-11 12:53:24 +0100779 buf[3] = (u8) (0x0F0 & IUU_ONE_STOP_BIT) | (0x07 & IUU_PARITY_EVEN);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200780
781 status = bulk_immediate(port, buf, 4);
782 if (status != IUU_OPERATION_OK) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700783 dev_dbg(&port->dev, "%s - uart_on error\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200784 goto uart_enable_failed;
785 }
786 /* iuu_reset() the card after iuu_uart_on() */
787 status = iuu_uart_flush(port);
788 if (status != IUU_OPERATION_OK)
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700789 dev_dbg(&port->dev, "%s - uart_flush error\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200790uart_enable_failed:
791 kfree(buf);
792 return status;
793}
794
795/* Diables the IUU UART (a.k.a. the Phoenix voiderface) */
796static int iuu_uart_off(struct usb_serial_port *port)
797{
798 int status;
799 u8 *buf;
800 buf = kmalloc(1, GFP_KERNEL);
801 if (!buf)
802 return -ENOMEM;
803 buf[0] = IUU_UART_DISABLE;
804
805 status = bulk_immediate(port, buf, 1);
806 if (status != IUU_OPERATION_OK)
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700807 dev_dbg(&port->dev, "%s - uart_off error\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200808
809 kfree(buf);
810 return status;
811}
812
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100813static int iuu_uart_baud(struct usb_serial_port *port, u32 baud_base,
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200814 u32 *actual, u8 parity)
815{
816 int status;
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100817 u32 baud;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200818 u8 *dataout;
819 u8 DataCount = 0;
820 u8 T1Frekvens = 0;
821 u8 T1reload = 0;
822 unsigned int T1FrekvensHZ = 0;
823
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700824 dev_dbg(&port->dev, "%s - enter baud_base=%d\n", __func__, baud_base);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200825 dataout = kmalloc(sizeof(u8) * 5, GFP_KERNEL);
826
827 if (!dataout)
828 return -ENOMEM;
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100829 /*baud = (((priv->clk / 35) * baud_base) / 100000); */
830 baud = baud_base;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200831
832 if (baud < 1200 || baud > 230400) {
833 kfree(dataout);
834 return IUU_INVALID_PARAMETER;
835 }
836 if (baud > 977) {
837 T1Frekvens = 3;
838 T1FrekvensHZ = 500000;
839 }
840
841 if (baud > 3906) {
842 T1Frekvens = 2;
843 T1FrekvensHZ = 2000000;
844 }
845
846 if (baud > 11718) {
847 T1Frekvens = 1;
848 T1FrekvensHZ = 6000000;
849 }
850
851 if (baud > 46875) {
852 T1Frekvens = 0;
853 T1FrekvensHZ = 24000000;
854 }
855
856 T1reload = 256 - (u8) (T1FrekvensHZ / (baud * 2));
857
858 /* magic number here: ENTER_FIRMWARE_UPDATE; */
859 dataout[DataCount++] = IUU_UART_ESC;
860 /* magic number here: CHANGE_BAUD; */
861 dataout[DataCount++] = IUU_UART_CHANGE;
862 dataout[DataCount++] = T1Frekvens;
863 dataout[DataCount++] = T1reload;
864
865 *actual = (T1FrekvensHZ / (256 - T1reload)) / 2;
866
867 switch (parity & 0x0F) {
868 case IUU_PARITY_NONE:
869 dataout[DataCount++] = 0x00;
870 break;
871 case IUU_PARITY_EVEN:
872 dataout[DataCount++] = 0x01;
873 break;
874 case IUU_PARITY_ODD:
875 dataout[DataCount++] = 0x02;
876 break;
877 case IUU_PARITY_MARK:
878 dataout[DataCount++] = 0x03;
879 break;
880 case IUU_PARITY_SPACE:
881 dataout[DataCount++] = 0x04;
882 break;
883 default:
884 kfree(dataout);
885 return IUU_INVALID_PARAMETER;
886 break;
887 }
888
889 switch (parity & 0xF0) {
890 case IUU_ONE_STOP_BIT:
891 dataout[DataCount - 1] |= IUU_ONE_STOP_BIT;
892 break;
893
894 case IUU_TWO_STOP_BITS:
895 dataout[DataCount - 1] |= IUU_TWO_STOP_BITS;
896 break;
897 default:
898 kfree(dataout);
899 return IUU_INVALID_PARAMETER;
900 break;
901 }
902
903 status = bulk_immediate(port, dataout, DataCount);
904 if (status != IUU_OPERATION_OK)
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700905 dev_dbg(&port->dev, "%s - uart_off error\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200906 kfree(dataout);
907 return status;
908}
909
Olivier Bornet96dab772009-06-11 12:54:20 +0100910static void iuu_set_termios(struct tty_struct *tty,
911 struct usb_serial_port *port, struct ktermios *old_termios)
912{
913 const u32 supported_mask = CMSPAR|PARENB|PARODD;
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100914 struct iuu_private *priv = usb_get_serial_port_data(port);
Olivier Bornet96dab772009-06-11 12:54:20 +0100915 unsigned int cflag = tty->termios->c_cflag;
916 int status;
917 u32 actual;
918 u32 parity;
919 int csize = CS7;
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100920 int baud;
Olivier Bornet96dab772009-06-11 12:54:20 +0100921 u32 newval = cflag & supported_mask;
922
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100923 /* Just use the ospeed. ispeed should be the same. */
924 baud = tty->termios->c_ospeed;
925
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700926 dev_dbg(&port->dev, "%s - enter c_ospeed or baud=%d\n", __func__, baud);
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100927
Olivier Bornet96dab772009-06-11 12:54:20 +0100928 /* compute the parity parameter */
929 parity = 0;
930 if (cflag & CMSPAR) { /* Using mark space */
931 if (cflag & PARODD)
932 parity |= IUU_PARITY_SPACE;
933 else
934 parity |= IUU_PARITY_MARK;
935 } else if (!(cflag & PARENB)) {
936 parity |= IUU_PARITY_NONE;
937 csize = CS8;
938 } else if (cflag & PARODD)
939 parity |= IUU_PARITY_ODD;
940 else
941 parity |= IUU_PARITY_EVEN;
942
943 parity |= (cflag & CSTOPB ? IUU_TWO_STOP_BITS : IUU_ONE_STOP_BIT);
944
945 /* set it */
946 status = iuu_uart_baud(port,
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100947 baud * priv->boost / 100,
Olivier Bornet96dab772009-06-11 12:54:20 +0100948 &actual, parity);
949
950 /* set the termios value to the real one, so the user now what has
951 * changed. We support few fields so its easies to copy the old hw
952 * settings back over and then adjust them
953 */
James Courtier-Dutton89b54392010-05-21 11:53:25 +0100954 if (old_termios)
955 tty_termios_copy_hw(tty->termios, old_termios);
Olivier Bornet96dab772009-06-11 12:54:20 +0100956 if (status != 0) /* Set failed - return old bits */
957 return;
958 /* Re-encode speed, parity and csize */
959 tty_encode_baud_rate(tty, baud, baud);
960 tty->termios->c_cflag &= ~(supported_mask|CSIZE);
961 tty->termios->c_cflag |= newval | csize;
962}
963
Alan Cox335f8512009-06-11 12:26:29 +0100964static void iuu_close(struct usb_serial_port *port)
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200965{
966 /* iuu_led (port,255,0,0,0); */
967 struct usb_serial *serial;
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200968
969 serial = port->serial;
970 if (!serial)
971 return;
972
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200973 iuu_uart_off(port);
974 if (serial->dev) {
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200975 /* free writebuf */
976 /* shutdown our urbs */
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -0700977 dev_dbg(&port->dev, "%s - shutting down urbs\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200978 usb_kill_urb(port->write_urb);
979 usb_kill_urb(port->read_urb);
980 usb_kill_urb(port->interrupt_in_urb);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200981 iuu_led(port, 0, 0, 0xF000, 0xFF);
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200982 }
983}
984
Alan Coxfe1ae7f2009-09-19 13:13:33 -0700985static void iuu_init_termios(struct tty_struct *tty)
986{
987 *(tty->termios) = tty_std_termios;
988 tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
989 | TIOCM_CTS | CSTOPB | PARENB;
990 tty->termios->c_ispeed = 9600;
991 tty->termios->c_ospeed = 9600;
992 tty->termios->c_lflag = 0;
993 tty->termios->c_oflag = 0;
994 tty->termios->c_iflag = 0;
995}
996
Alan Coxa509a7e2009-09-19 13:13:26 -0700997static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
Alain Degreffe60a8fc02007-10-26 13:51:49 +0200998{
999 struct usb_serial *serial = port->serial;
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -07001000 struct device *dev = &port->dev;
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001001 u8 *buf;
1002 int result;
James Courtier-Dutton89b54392010-05-21 11:53:25 +01001003 int baud;
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001004 u32 actual;
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001005 struct iuu_private *priv = usb_get_serial_port_data(port);
1006
James Courtier-Dutton89b54392010-05-21 11:53:25 +01001007 baud = tty->termios->c_ospeed;
1008 tty->termios->c_ispeed = baud;
1009 /* Re-encode speed */
1010 tty_encode_baud_rate(tty, baud, baud);
1011
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -07001012 dev_dbg(dev, "%s - baud %d\n", __func__, baud);
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001013 usb_clear_halt(serial->dev, port->write_urb->pipe);
1014 usb_clear_halt(serial->dev, port->read_urb->pipe);
1015
1016 buf = kmalloc(10, GFP_KERNEL);
1017 if (buf == NULL)
1018 return -ENOMEM;
1019
Alan Coxfe1ae7f2009-09-19 13:13:33 -07001020 priv->poll = 0;
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001021
1022 /* initialize writebuf */
1023#define FISH(a, b, c, d) do { \
1024 result = usb_control_msg(port->serial->dev, \
1025 usb_rcvctrlpipe(port->serial->dev, 0), \
1026 b, a, c, d, buf, 1, 1000); \
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -07001027 dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n", a, b, c, d, result, \
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001028 buf[0]); } while (0);
1029
1030#define SOUP(a, b, c, d) do { \
1031 result = usb_control_msg(port->serial->dev, \
1032 usb_sndctrlpipe(port->serial->dev, 0), \
1033 b, a, c, d, NULL, 0, 1000); \
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -07001034 dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x %d\n", a, b, c, d, result); } while (0)
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001035
1036 /* This is not UART related but IUU USB driver related or something */
1037 /* like that. Basically no IUU will accept any commands from the USB */
1038 /* host unless it has received the following message */
1039 /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */
1040
1041 SOUP(0x03, 0x02, 0x02, 0x0);
1042 kfree(buf);
1043 iuu_led(port, 0xF000, 0xF000, 0, 0xFF);
1044 iuu_uart_on(port);
1045 if (boost < 100)
1046 boost = 100;
James Courtier-Dutton89b54392010-05-21 11:53:25 +01001047 priv->boost = boost;
1048 priv->baud = baud;
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001049 switch (clockmode) {
1050 case 2: /* 3.680 Mhz */
James Courtier-Dutton89b54392010-05-21 11:53:25 +01001051 priv->clk = IUU_CLK_3680000;
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001052 iuu_clk(port, IUU_CLK_3680000 * boost / 100);
1053 result =
James Courtier-Dutton89b54392010-05-21 11:53:25 +01001054 iuu_uart_baud(port, baud * boost / 100, &actual,
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001055 IUU_PARITY_EVEN);
1056 break;
1057 case 3: /* 6.00 Mhz */
1058 iuu_clk(port, IUU_CLK_6000000 * boost / 100);
James Courtier-Dutton89b54392010-05-21 11:53:25 +01001059 priv->clk = IUU_CLK_6000000;
1060 /* Ratio of 6000000 to 3500000 for baud 9600 */
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001061 result =
1062 iuu_uart_baud(port, 16457 * boost / 100, &actual,
1063 IUU_PARITY_EVEN);
1064 break;
1065 default: /* 3.579 Mhz */
1066 iuu_clk(port, IUU_CLK_3579000 * boost / 100);
James Courtier-Dutton89b54392010-05-21 11:53:25 +01001067 priv->clk = IUU_CLK_3579000;
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001068 result =
James Courtier-Dutton89b54392010-05-21 11:53:25 +01001069 iuu_uart_baud(port, baud * boost / 100, &actual,
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001070 IUU_PARITY_EVEN);
1071 }
1072
1073 /* set the cardin cardout signals */
1074 switch (cdmode) {
1075 case 0:
1076 iuu_cardin = 0;
1077 iuu_cardout = 0;
1078 break;
1079 case 1:
1080 iuu_cardin = TIOCM_CD;
1081 iuu_cardout = 0;
1082 break;
1083 case 2:
1084 iuu_cardin = 0;
1085 iuu_cardout = TIOCM_CD;
1086 break;
1087 case 3:
1088 iuu_cardin = TIOCM_DSR;
1089 iuu_cardout = 0;
1090 break;
1091 case 4:
1092 iuu_cardin = 0;
1093 iuu_cardout = TIOCM_DSR;
1094 break;
1095 case 5:
1096 iuu_cardin = TIOCM_CTS;
1097 iuu_cardout = 0;
1098 break;
1099 case 6:
1100 iuu_cardin = 0;
1101 iuu_cardout = TIOCM_CTS;
1102 break;
1103 case 7:
1104 iuu_cardin = TIOCM_RNG;
1105 iuu_cardout = 0;
1106 break;
1107 case 8:
1108 iuu_cardin = 0;
1109 iuu_cardout = TIOCM_RNG;
1110 }
1111
1112 iuu_uart_flush(port);
1113
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -07001114 dev_dbg(dev, "%s - initialization done\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001115
1116 memset(port->write_urb->transfer_buffer, IUU_UART_RX, 1);
1117 usb_fill_bulk_urb(port->write_urb, port->serial->dev,
1118 usb_sndbulkpipe(port->serial->dev,
1119 port->bulk_out_endpointAddress),
1120 port->write_urb->transfer_buffer, 1,
1121 read_rxcmd_callback, port);
1122 result = usb_submit_urb(port->write_urb, GFP_KERNEL);
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001123 if (result) {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -07001124 dev_err(dev, "%s - failed submitting read urb, error %d\n", __func__, result);
Alan Cox335f8512009-06-11 12:26:29 +01001125 iuu_close(port);
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001126 } else {
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -07001127 dev_dbg(dev, "%s - rxcmd OK\n", __func__);
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001128 }
Johan Hovoldb58a6462011-11-10 14:58:30 +01001129
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001130 return result;
1131}
1132
Olivier Bornet20eda942009-08-18 21:05:55 +02001133/* how to change VCC */
1134static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc)
1135{
1136 int status;
1137 u8 *buf;
1138
1139 buf = kmalloc(5, GFP_KERNEL);
1140 if (!buf)
1141 return -ENOMEM;
1142
Olivier Bornet20eda942009-08-18 21:05:55 +02001143 buf[0] = IUU_SET_VCC;
1144 buf[1] = vcc & 0xFF;
1145 buf[2] = (vcc >> 8) & 0xFF;
1146 buf[3] = (vcc >> 16) & 0xFF;
1147 buf[4] = (vcc >> 24) & 0xFF;
1148
1149 status = bulk_immediate(port, buf, 5);
1150 kfree(buf);
1151
1152 if (status != IUU_OPERATION_OK)
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -07001153 dev_dbg(&port->dev, "%s - vcc error status = %2x\n", __func__, status);
Olivier Bornet20eda942009-08-18 21:05:55 +02001154 else
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -07001155 dev_dbg(&port->dev, "%s - vcc OK !\n", __func__);
Olivier Bornet20eda942009-08-18 21:05:55 +02001156
1157 return status;
1158}
1159
1160/*
1161 * Sysfs Attributes
1162 */
1163
1164static ssize_t show_vcc_mode(struct device *dev,
1165 struct device_attribute *attr, char *buf)
1166{
1167 struct usb_serial_port *port = to_usb_serial_port(dev);
1168 struct iuu_private *priv = usb_get_serial_port_data(port);
1169
1170 return sprintf(buf, "%d\n", priv->vcc);
1171}
1172
1173static ssize_t store_vcc_mode(struct device *dev,
1174 struct device_attribute *attr, const char *buf, size_t count)
1175{
1176 struct usb_serial_port *port = to_usb_serial_port(dev);
1177 struct iuu_private *priv = usb_get_serial_port_data(port);
1178 unsigned long v;
1179
1180 if (strict_strtoul(buf, 10, &v)) {
1181 dev_err(dev, "%s - vcc_mode: %s is not a unsigned long\n",
1182 __func__, buf);
1183 goto fail_store_vcc_mode;
1184 }
1185
Greg Kroah-Hartman2621cee2012-09-14 15:08:28 -07001186 dev_dbg(dev, "%s: setting vcc_mode = %ld", __func__, v);
Olivier Bornet20eda942009-08-18 21:05:55 +02001187
1188 if ((v != 3) && (v != 5)) {
1189 dev_err(dev, "%s - vcc_mode %ld is invalid\n", __func__, v);
1190 } else {
1191 iuu_vcc_set(port, v);
1192 priv->vcc = v;
1193 }
1194fail_store_vcc_mode:
1195 return count;
1196}
1197
1198static DEVICE_ATTR(vcc_mode, S_IRUSR | S_IWUSR, show_vcc_mode,
1199 store_vcc_mode);
1200
1201static int iuu_create_sysfs_attrs(struct usb_serial_port *port)
1202{
Olivier Bornet20eda942009-08-18 21:05:55 +02001203 return device_create_file(&port->dev, &dev_attr_vcc_mode);
1204}
1205
1206static int iuu_remove_sysfs_attrs(struct usb_serial_port *port)
1207{
Olivier Bornet20eda942009-08-18 21:05:55 +02001208 device_remove_file(&port->dev, &dev_attr_vcc_mode);
1209 return 0;
1210}
1211
1212/*
1213 * End Sysfs Attributes
1214 */
1215
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001216static struct usb_serial_driver iuu_device = {
1217 .driver = {
1218 .owner = THIS_MODULE,
1219 .name = "iuu_phoenix",
1220 },
1221 .id_table = id_table,
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001222 .num_ports = 1,
Johan Hovoldbbcb2b92010-03-17 23:00:37 +01001223 .bulk_in_size = 512,
1224 .bulk_out_size = 512,
Olivier Bornet20eda942009-08-18 21:05:55 +02001225 .port_probe = iuu_create_sysfs_attrs,
1226 .port_remove = iuu_remove_sysfs_attrs,
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001227 .open = iuu_open,
1228 .close = iuu_close,
1229 .write = iuu_uart_write,
1230 .read_bulk_callback = iuu_uart_read_callback,
1231 .tiocmget = iuu_tiocmget,
1232 .tiocmset = iuu_tiocmset,
Olivier Bornet96dab772009-06-11 12:54:20 +01001233 .set_termios = iuu_set_termios,
Alan Coxfe1ae7f2009-09-19 13:13:33 -07001234 .init_termios = iuu_init_termios,
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001235 .attach = iuu_startup,
Alan Sternf9c99bb2009-06-02 11:53:55 -04001236 .release = iuu_release,
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001237};
1238
Alan Stern7dbe2462012-02-23 14:56:57 -05001239static struct usb_serial_driver * const serial_drivers[] = {
1240 &iuu_device, NULL
1241};
1242
Greg Kroah-Hartman68e24112012-05-08 15:46:14 -07001243module_usb_serial_driver(serial_drivers, id_table);
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001244
1245MODULE_AUTHOR("Alain Degreffe eczema@ecze.com");
1246
1247MODULE_DESCRIPTION(DRIVER_DESC);
1248MODULE_LICENSE("GPL");
1249
1250MODULE_VERSION(DRIVER_VERSION);
1251module_param(debug, bool, S_IRUGO | S_IWUSR);
1252MODULE_PARM_DESC(debug, "Debug enabled or not");
1253
1254module_param(xmas, bool, S_IRUGO | S_IWUSR);
Olivier Bornet8844a322009-08-18 21:05:54 +02001255MODULE_PARM_DESC(xmas, "Xmas colors enabled or not");
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001256
1257module_param(boost, int, S_IRUGO | S_IWUSR);
Olivier Bornet8844a322009-08-18 21:05:54 +02001258MODULE_PARM_DESC(boost, "Card overclock boost (in percent 100-500)");
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001259
1260module_param(clockmode, int, S_IRUGO | S_IWUSR);
Olivier Bornet8844a322009-08-18 21:05:54 +02001261MODULE_PARM_DESC(clockmode, "Card clock mode (1=3.579 MHz, 2=3.680 MHz, "
1262 "3=6 Mhz)");
Alain Degreffe60a8fc02007-10-26 13:51:49 +02001263
1264module_param(cdmode, int, S_IRUGO | S_IWUSR);
Olivier Bornet8844a322009-08-18 21:05:54 +02001265MODULE_PARM_DESC(cdmode, "Card detect mode (0=none, 1=CD, 2=!CD, 3=DSR, "
1266 "4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING)");
Olivier Bornete55c6d02009-08-18 21:05:57 +02001267
1268module_param(vcc_default, int, S_IRUGO | S_IWUSR);
1269MODULE_PARM_DESC(vcc_default, "Set default VCC (either 3 for 3.3V or 5 "
1270 "for 5V). Default to 5.");