blob: 246c5572667b141e139705f1718c84d4410ad3a6 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * icom.c
3 *
4 * Copyright (C) 2001 IBM Corporation. All rights reserved.
5 *
6 * Serial device driver.
7 *
8 * Based on code from serial.c
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 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25#define SERIAL_DO_RESTART
26#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/kernel.h>
28#include <linux/errno.h>
29#include <linux/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/timer.h>
31#include <linux/interrupt.h>
32#include <linux/tty.h>
33#include <linux/termios.h>
34#include <linux/fs.h>
35#include <linux/tty_flip.h>
36#include <linux/serial.h>
37#include <linux/serial_reg.h>
38#include <linux/major.h>
39#include <linux/string.h>
40#include <linux/fcntl.h>
41#include <linux/ptrace.h>
42#include <linux/ioport.h>
43#include <linux/mm.h>
44#include <linux/slab.h>
45#include <linux/init.h>
46#include <linux/delay.h>
47#include <linux/pci.h>
48#include <linux/vmalloc.h>
49#include <linux/smp.h>
50#include <linux/smp_lock.h>
51#include <linux/spinlock.h>
52#include <linux/kobject.h>
53#include <linux/firmware.h>
54#include <linux/bitops.h>
55
56#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#include <asm/io.h>
58#include <asm/irq.h>
59#include <asm/uaccess.h>
60
61#include "icom.h"
62
63/*#define ICOM_TRACE enable port trace capabilities */
64
65#define ICOM_DRIVER_NAME "icom"
66#define ICOM_VERSION_STR "1.3.1"
67#define NR_PORTS 128
68#define ICOM_PORT ((struct icom_port *)port)
69#define to_icom_adapter(d) container_of(d, struct icom_adapter, kobj)
70
71static const struct pci_device_id icom_pci_table[] = {
72 {
73 .vendor = PCI_VENDOR_ID_IBM,
74 .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1,
75 .subvendor = PCI_ANY_ID,
76 .subdevice = PCI_ANY_ID,
77 .driver_data = ADAPTER_V1,
78 },
79 {
80 .vendor = PCI_VENDOR_ID_IBM,
81 .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
82 .subvendor = PCI_VENDOR_ID_IBM,
83 .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX,
84 .driver_data = ADAPTER_V2,
85 },
86 {
87 .vendor = PCI_VENDOR_ID_IBM,
88 .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
89 .subvendor = PCI_VENDOR_ID_IBM,
90 .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM,
91 .driver_data = ADAPTER_V2,
92 },
93 {
94 .vendor = PCI_VENDOR_ID_IBM,
95 .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
96 .subvendor = PCI_VENDOR_ID_IBM,
97 .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL,
98 .driver_data = ADAPTER_V2,
99 },
100 {}
101};
102
103struct lookup_proc_table start_proc[4] = {
104 {NULL, ICOM_CONTROL_START_A},
105 {NULL, ICOM_CONTROL_START_B},
106 {NULL, ICOM_CONTROL_START_C},
107 {NULL, ICOM_CONTROL_START_D}
108};
109
110
111struct lookup_proc_table stop_proc[4] = {
112 {NULL, ICOM_CONTROL_STOP_A},
113 {NULL, ICOM_CONTROL_STOP_B},
114 {NULL, ICOM_CONTROL_STOP_C},
115 {NULL, ICOM_CONTROL_STOP_D}
116};
117
118struct lookup_int_table int_mask_tbl[4] = {
119 {NULL, ICOM_INT_MASK_PRC_A},
120 {NULL, ICOM_INT_MASK_PRC_B},
121 {NULL, ICOM_INT_MASK_PRC_C},
122 {NULL, ICOM_INT_MASK_PRC_D},
123};
124
125
126MODULE_DEVICE_TABLE(pci, icom_pci_table);
127
128static LIST_HEAD(icom_adapter_head);
129
130/* spinlock for adapter initialization and changing adapter operations */
131static spinlock_t icom_lock;
132
133#ifdef ICOM_TRACE
134static inline void trace(struct icom_port *, char *, unsigned long) {};
135#else
136static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
137#endif
138
139static void free_port_memory(struct icom_port *icom_port)
140{
141 struct pci_dev *dev = icom_port->adapter->pci_dev;
142
143 trace(icom_port, "RET_PORT_MEM", 0);
144 if (icom_port->recv_buf) {
145 pci_free_consistent(dev, 4096, icom_port->recv_buf,
146 icom_port->recv_buf_pci);
147 icom_port->recv_buf = NULL;
148 }
149 if (icom_port->xmit_buf) {
150 pci_free_consistent(dev, 4096, icom_port->xmit_buf,
151 icom_port->xmit_buf_pci);
152 icom_port->xmit_buf = NULL;
153 }
154 if (icom_port->statStg) {
155 pci_free_consistent(dev, 4096, icom_port->statStg,
156 icom_port->statStg_pci);
157 icom_port->statStg = NULL;
158 }
159
160 if (icom_port->xmitRestart) {
161 pci_free_consistent(dev, 4096, icom_port->xmitRestart,
162 icom_port->xmitRestart_pci);
163 icom_port->xmitRestart = NULL;
164 }
165}
166
Jiri Slaby98f85d32007-04-23 14:41:20 -0700167static int __devinit get_port_memory(struct icom_port *icom_port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168{
169 int index;
170 unsigned long stgAddr;
171 unsigned long startStgAddr;
172 unsigned long offset;
173 struct pci_dev *dev = icom_port->adapter->pci_dev;
174
175 icom_port->xmit_buf =
176 pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci);
177 if (!icom_port->xmit_buf) {
178 dev_err(&dev->dev, "Can not allocate Transmit buffer\n");
179 return -ENOMEM;
180 }
181
182 trace(icom_port, "GET_PORT_MEM",
183 (unsigned long) icom_port->xmit_buf);
184
185 icom_port->recv_buf =
186 pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci);
187 if (!icom_port->recv_buf) {
188 dev_err(&dev->dev, "Can not allocate Receive buffer\n");
189 free_port_memory(icom_port);
190 return -ENOMEM;
191 }
192 trace(icom_port, "GET_PORT_MEM",
193 (unsigned long) icom_port->recv_buf);
194
195 icom_port->statStg =
196 pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci);
197 if (!icom_port->statStg) {
198 dev_err(&dev->dev, "Can not allocate Status buffer\n");
199 free_port_memory(icom_port);
200 return -ENOMEM;
201 }
202 trace(icom_port, "GET_PORT_MEM",
203 (unsigned long) icom_port->statStg);
204
205 icom_port->xmitRestart =
206 pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci);
207 if (!icom_port->xmitRestart) {
208 dev_err(&dev->dev,
209 "Can not allocate xmit Restart buffer\n");
210 free_port_memory(icom_port);
211 return -ENOMEM;
212 }
213
214 memset(icom_port->statStg, 0, 4096);
215
216 /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that
217 indicates that frames are to be transmitted
218 */
219
220 stgAddr = (unsigned long) icom_port->statStg;
221 for (index = 0; index < NUM_XBUFFS; index++) {
222 trace(icom_port, "FOD_ADDR", stgAddr);
223 stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]);
224 if (index < (NUM_XBUFFS - 1)) {
225 memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
226 icom_port->statStg->xmit[index].leLengthASD =
227 (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
228 trace(icom_port, "FOD_ADDR", stgAddr);
229 trace(icom_port, "FOD_XBUFF",
230 (unsigned long) icom_port->xmit_buf);
231 icom_port->statStg->xmit[index].leBuffer =
232 cpu_to_le32(icom_port->xmit_buf_pci);
233 } else if (index == (NUM_XBUFFS - 1)) {
234 memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
235 icom_port->statStg->xmit[index].leLengthASD =
236 (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
237 trace(icom_port, "FOD_XBUFF",
238 (unsigned long) icom_port->xmit_buf);
239 icom_port->statStg->xmit[index].leBuffer =
240 cpu_to_le32(icom_port->xmit_buf_pci);
241 } else {
242 memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
243 }
244 }
245 /* FIDs */
246 startStgAddr = stgAddr;
247
248 /* fill in every entry, even if no buffer */
249 for (index = 0; index < NUM_RBUFFS; index++) {
250 trace(icom_port, "FID_ADDR", stgAddr);
251 stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]);
252 icom_port->statStg->rcv[index].leLength = 0;
253 icom_port->statStg->rcv[index].WorkingLength =
254 (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
255 if (index < (NUM_RBUFFS - 1) ) {
256 offset = stgAddr - (unsigned long) icom_port->statStg;
257 icom_port->statStg->rcv[index].leNext =
258 cpu_to_le32(icom_port-> statStg_pci + offset);
259 trace(icom_port, "FID_RBUFF",
260 (unsigned long) icom_port->recv_buf);
261 icom_port->statStg->rcv[index].leBuffer =
262 cpu_to_le32(icom_port->recv_buf_pci);
263 } else if (index == (NUM_RBUFFS -1) ) {
264 offset = startStgAddr - (unsigned long) icom_port->statStg;
265 icom_port->statStg->rcv[index].leNext =
266 cpu_to_le32(icom_port-> statStg_pci + offset);
267 trace(icom_port, "FID_RBUFF",
268 (unsigned long) icom_port->recv_buf + 2048);
269 icom_port->statStg->rcv[index].leBuffer =
270 cpu_to_le32(icom_port->recv_buf_pci + 2048);
271 } else {
272 icom_port->statStg->rcv[index].leNext = 0;
273 icom_port->statStg->rcv[index].leBuffer = 0;
274 }
275 }
276
277 return 0;
278}
279
280static void stop_processor(struct icom_port *icom_port)
281{
282 unsigned long temp;
283 unsigned long flags;
284 int port;
285
286 spin_lock_irqsave(&icom_lock, flags);
287
288 port = icom_port->port;
289 if (port == 0 || port == 1)
290 stop_proc[port].global_control_reg = &icom_port->global_reg->control;
291 else
292 stop_proc[port].global_control_reg = &icom_port->global_reg->control_2;
293
294
295 if (port < 4) {
296 temp = readl(stop_proc[port].global_control_reg);
297 temp =
298 (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
299 writel(temp, stop_proc[port].global_control_reg);
300
301 /* write flush */
302 readl(stop_proc[port].global_control_reg);
303 } else {
304 dev_err(&icom_port->adapter->pci_dev->dev,
305 "Invalid port assignment\n");
306 }
307
308 spin_unlock_irqrestore(&icom_lock, flags);
309}
310
311static void start_processor(struct icom_port *icom_port)
312{
313 unsigned long temp;
314 unsigned long flags;
315 int port;
316
317 spin_lock_irqsave(&icom_lock, flags);
318
319 port = icom_port->port;
320 if (port == 0 || port == 1)
321 start_proc[port].global_control_reg = &icom_port->global_reg->control;
322 else
323 start_proc[port].global_control_reg = &icom_port->global_reg->control_2;
324 if (port < 4) {
325 temp = readl(start_proc[port].global_control_reg);
326 temp =
327 (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
328 writel(temp, start_proc[port].global_control_reg);
329
330 /* write flush */
331 readl(start_proc[port].global_control_reg);
332 } else {
333 dev_err(&icom_port->adapter->pci_dev->dev,
334 "Invalid port assignment\n");
335 }
336
337 spin_unlock_irqrestore(&icom_lock, flags);
338}
339
340static void load_code(struct icom_port *icom_port)
341{
342 const struct firmware *fw;
343 char __iomem *iram_ptr;
344 int index;
345 int status = 0;
346 void __iomem *dram_ptr = icom_port->dram;
347 dma_addr_t temp_pci;
348 unsigned char *new_page = NULL;
349 unsigned char cable_id = NO_CABLE;
350 struct pci_dev *dev = icom_port->adapter->pci_dev;
351
352 /* Clear out any pending interrupts */
353 writew(0x3FFF, icom_port->int_reg);
354
355 trace(icom_port, "CLEAR_INTERRUPTS", 0);
356
357 /* Stop processor */
358 stop_processor(icom_port);
359
360 /* Zero out DRAM */
361 memset_io(dram_ptr, 0, 512);
362
363 /* Load Call Setup into Adapter */
364 if (request_firmware(&fw, "icom_call_setup.bin", &dev->dev) < 0) {
365 dev_err(&dev->dev,"Unable to load icom_call_setup.bin firmware image\n");
366 status = -1;
367 goto load_code_exit;
368 }
369
370 if (fw->size > ICOM_DCE_IRAM_OFFSET) {
371 dev_err(&dev->dev, "Invalid firmware image for icom_call_setup.bin found.\n");
372 release_firmware(fw);
373 status = -1;
374 goto load_code_exit;
375 }
376
377 iram_ptr = (char __iomem *)icom_port->dram + ICOM_IRAM_OFFSET;
378 for (index = 0; index < fw->size; index++)
379 writeb(fw->data[index], &iram_ptr[index]);
380
381 release_firmware(fw);
382
383 /* Load Resident DCE portion of Adapter */
384 if (request_firmware(&fw, "icom_res_dce.bin", &dev->dev) < 0) {
385 dev_err(&dev->dev,"Unable to load icom_res_dce.bin firmware image\n");
386 status = -1;
387 goto load_code_exit;
388 }
389
390 if (fw->size > ICOM_IRAM_SIZE) {
391 dev_err(&dev->dev, "Invalid firmware image for icom_res_dce.bin found.\n");
392 release_firmware(fw);
393 status = -1;
394 goto load_code_exit;
395 }
396
397 iram_ptr = (char __iomem *) icom_port->dram + ICOM_IRAM_OFFSET;
398 for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++)
399 writeb(fw->data[index], &iram_ptr[index]);
400
401 release_firmware(fw);
402
403 /* Set Hardware level */
404 if ((icom_port->adapter->version | ADAPTER_V2) == ADAPTER_V2)
405 writeb(V2_HARDWARE, &(icom_port->dram->misc_flags));
406
407 /* Start the processor in Adapter */
408 start_processor(icom_port);
409
410 writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL),
411 &(icom_port->dram->HDLCConfigReg));
412 writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */
413 writeb(0x00, &(icom_port->dram->CmdReg));
414 writeb(0x10, &(icom_port->dram->async_config3));
415 writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC |
416 ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2));
417
418 /*Set up data in icom DRAM to indicate where personality
419 *code is located and its length.
420 */
421 new_page = pci_alloc_consistent(dev, 4096, &temp_pci);
422
423 if (!new_page) {
424 dev_err(&dev->dev, "Can not allocate DMA buffer\n");
425 status = -1;
426 goto load_code_exit;
427 }
428
429 if (request_firmware(&fw, "icom_asc.bin", &dev->dev) < 0) {
430 dev_err(&dev->dev,"Unable to load icom_asc.bin firmware image\n");
431 status = -1;
432 goto load_code_exit;
433 }
434
435 if (fw->size > ICOM_DCE_IRAM_OFFSET) {
436 dev_err(&dev->dev, "Invalid firmware image for icom_asc.bin found.\n");
437 release_firmware(fw);
438 status = -1;
439 goto load_code_exit;
440 }
441
442 for (index = 0; index < fw->size; index++)
443 new_page[index] = fw->data[index];
444
445 release_firmware(fw);
446
447 writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length);
448 writel(temp_pci, &icom_port->dram->mac_load_addr);
449
450 /*Setting the syncReg to 0x80 causes adapter to start downloading
451 the personality code into adapter instruction RAM.
452 Once code is loaded, it will begin executing and, based on
453 information provided above, will start DMAing data from
454 shared memory to adapter DRAM.
455 */
456 /* the wait loop below verifies this write operation has been done
457 and processed
458 */
459 writeb(START_DOWNLOAD, &icom_port->dram->sync);
460
461 /* Wait max 1 Sec for data download and processor to start */
462 for (index = 0; index < 10; index++) {
463 msleep(100);
464 if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE)
465 break;
466 }
467
468 if (index == 10)
469 status = -1;
470
471 /*
472 * check Cable ID
473 */
474 cable_id = readb(&icom_port->dram->cable_id);
475
476 if (cable_id & ICOM_CABLE_ID_VALID) {
477 /* Get cable ID into the lower 4 bits (standard form) */
478 cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4;
479 icom_port->cable_id = cable_id;
480 } else {
481 dev_err(&dev->dev,"Invalid or no cable attached\n");
482 icom_port->cable_id = NO_CABLE;
483 }
484
485 load_code_exit:
486
487 if (status != 0) {
488 /* Clear out any pending interrupts */
489 writew(0x3FFF, icom_port->int_reg);
490
491 /* Turn off port */
492 writeb(ICOM_DISABLE, &(icom_port->dram->disable));
493
494 /* Stop processor */
495 stop_processor(icom_port);
496
497 dev_err(&icom_port->adapter->pci_dev->dev,"Port not opertional\n");
498 }
499
500 if (new_page != NULL)
501 pci_free_consistent(dev, 4096, new_page, temp_pci);
502}
503
504static int startup(struct icom_port *icom_port)
505{
506 unsigned long temp;
507 unsigned char cable_id, raw_cable_id;
508 unsigned long flags;
509 int port;
510
511 trace(icom_port, "STARTUP", 0);
512
513 if (!icom_port->dram) {
514 /* should NEVER be NULL */
515 dev_err(&icom_port->adapter->pci_dev->dev,
516 "Unusable Port, port configuration missing\n");
517 return -ENODEV;
518 }
519
520 /*
521 * check Cable ID
522 */
523 raw_cable_id = readb(&icom_port->dram->cable_id);
524 trace(icom_port, "CABLE_ID", raw_cable_id);
525
526 /* Get cable ID into the lower 4 bits (standard form) */
527 cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
528
529 /* Check for valid Cable ID */
530 if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
531 (cable_id != icom_port->cable_id)) {
532
533 /* reload adapter code, pick up any potential changes in cable id */
534 load_code(icom_port);
535
536 /* still no sign of cable, error out */
537 raw_cable_id = readb(&icom_port->dram->cable_id);
538 cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
539 if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
540 (icom_port->cable_id == NO_CABLE))
541 return -EIO;
542 }
543
544 /*
545 * Finally, clear and enable interrupts
546 */
547 spin_lock_irqsave(&icom_lock, flags);
548 port = icom_port->port;
549 if (port == 0 || port == 1)
550 int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
551 else
552 int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
553
554 if (port == 0 || port == 2)
555 writew(0x00FF, icom_port->int_reg);
556 else
557 writew(0x3F00, icom_port->int_reg);
558 if (port < 4) {
559 temp = readl(int_mask_tbl[port].global_int_mask);
560 writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
561
562 /* write flush */
563 readl(int_mask_tbl[port].global_int_mask);
564 } else {
565 dev_err(&icom_port->adapter->pci_dev->dev,
566 "Invalid port assignment\n");
567 }
568
569 spin_unlock_irqrestore(&icom_lock, flags);
570 return 0;
571}
572
573static void shutdown(struct icom_port *icom_port)
574{
575 unsigned long temp;
576 unsigned char cmdReg;
577 unsigned long flags;
578 int port;
579
580 spin_lock_irqsave(&icom_lock, flags);
581 trace(icom_port, "SHUTDOWN", 0);
582
583 /*
584 * disable all interrupts
585 */
586 port = icom_port->port;
587 if (port == 0 || port == 1)
588 int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
589 else
590 int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
591
592 if (port < 4) {
593 temp = readl(int_mask_tbl[port].global_int_mask);
594 writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
595
596 /* write flush */
597 readl(int_mask_tbl[port].global_int_mask);
598 } else {
599 dev_err(&icom_port->adapter->pci_dev->dev,
600 "Invalid port assignment\n");
601 }
602 spin_unlock_irqrestore(&icom_lock, flags);
603
604 /*
605 * disable break condition
606 */
607 cmdReg = readb(&icom_port->dram->CmdReg);
608 if ((cmdReg | CMD_SND_BREAK) == CMD_SND_BREAK) {
609 writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);
610 }
611}
612
613static int icom_write(struct uart_port *port)
614{
615 unsigned long data_count;
616 unsigned char cmdReg;
617 unsigned long offset;
618 int temp_tail = port->info->xmit.tail;
619
620 trace(ICOM_PORT, "WRITE", 0);
621
622 if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
623 SA_FLAGS_READY_TO_XMIT) {
624 trace(ICOM_PORT, "WRITE_FULL", 0);
625 return 0;
626 }
627
628 data_count = 0;
629 while ((port->info->xmit.head != temp_tail) &&
630 (data_count <= XMIT_BUFF_SZ)) {
631
632 ICOM_PORT->xmit_buf[data_count++] =
633 port->info->xmit.buf[temp_tail];
634
635 temp_tail++;
636 temp_tail &= (UART_XMIT_SIZE - 1);
637 }
638
639 if (data_count) {
640 ICOM_PORT->statStg->xmit[0].flags =
641 cpu_to_le16(SA_FLAGS_READY_TO_XMIT);
642 ICOM_PORT->statStg->xmit[0].leLength =
643 cpu_to_le16(data_count);
644 offset =
645 (unsigned long) &ICOM_PORT->statStg->xmit[0] -
646 (unsigned long) ICOM_PORT->statStg;
647 *ICOM_PORT->xmitRestart =
648 cpu_to_le32(ICOM_PORT->statStg_pci + offset);
649 cmdReg = readb(&ICOM_PORT->dram->CmdReg);
650 writeb(cmdReg | CMD_XMIT_RCV_ENABLE,
651 &ICOM_PORT->dram->CmdReg);
652 writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd);
653 trace(ICOM_PORT, "WRITE_START", data_count);
654 /* write flush */
655 readb(&ICOM_PORT->dram->StartXmitCmd);
656 }
657
658 return data_count;
659}
660
661static inline void check_modem_status(struct icom_port *icom_port)
662{
663 static char old_status = 0;
664 char delta_status;
665 unsigned char status;
666
667 spin_lock(&icom_port->uart_port.lock);
668
669 /*modem input register */
670 status = readb(&icom_port->dram->isr);
671 trace(icom_port, "CHECK_MODEM", status);
672 delta_status = status ^ old_status;
673 if (delta_status) {
674 if (delta_status & ICOM_RI)
675 icom_port->uart_port.icount.rng++;
676 if (delta_status & ICOM_DSR)
677 icom_port->uart_port.icount.dsr++;
678 if (delta_status & ICOM_DCD)
679 uart_handle_dcd_change(&icom_port->uart_port,
680 delta_status & ICOM_DCD);
681 if (delta_status & ICOM_CTS)
682 uart_handle_cts_change(&icom_port->uart_port,
683 delta_status & ICOM_CTS);
684
685 wake_up_interruptible(&icom_port->uart_port.info->
686 delta_msr_wait);
687 old_status = status;
688 }
689 spin_unlock(&icom_port->uart_port.lock);
690}
691
692static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
693{
694 unsigned short int count;
695 int i;
696
697 if (port_int_reg & (INT_XMIT_COMPLETED)) {
698 trace(icom_port, "XMIT_COMPLETE", 0);
699
700 /* clear buffer in use bit */
701 icom_port->statStg->xmit[0].flags &=
702 cpu_to_le16(~SA_FLAGS_READY_TO_XMIT);
703
704 count = (unsigned short int)
705 cpu_to_le16(icom_port->statStg->xmit[0].leLength);
706 icom_port->uart_port.icount.tx += count;
707
708 for (i=0; i<count &&
709 !uart_circ_empty(&icom_port->uart_port.info->xmit); i++) {
710
711 icom_port->uart_port.info->xmit.tail++;
712 icom_port->uart_port.info->xmit.tail &=
713 (UART_XMIT_SIZE - 1);
714 }
715
716 if (!icom_write(&icom_port->uart_port))
717 /* activate write queue */
718 uart_write_wakeup(&icom_port->uart_port);
719 } else
720 trace(icom_port, "XMIT_DISABLED", 0);
721}
722
723static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
724{
725 short int count, rcv_buff;
726 struct tty_struct *tty = icom_port->uart_port.info->tty;
727 unsigned short int status;
728 struct uart_icount *icount;
729 unsigned long offset;
Alan Cox33f0f882006-01-09 20:54:13 -0800730 unsigned char flag;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731
732 trace(icom_port, "RCV_COMPLETE", 0);
733 rcv_buff = icom_port->next_rcv;
734
735 status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
736 while (status & SA_FL_RCV_DONE) {
Alan Cox33f0f882006-01-09 20:54:13 -0800737 int first = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 trace(icom_port, "FID_STATUS", status);
740 count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength);
741
Alan Cox33f0f882006-01-09 20:54:13 -0800742 count = tty_buffer_request_room(tty, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 trace(icom_port, "RCV_COUNT", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
745 trace(icom_port, "REAL_COUNT", count);
746
747 offset =
748 cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) -
749 icom_port->recv_buf_pci;
750
Alan Cox33f0f882006-01-09 20:54:13 -0800751 /* Block copy all but the last byte as this may have status */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if (count > 0) {
Alan Cox33f0f882006-01-09 20:54:13 -0800753 first = icom_port->recv_buf[offset];
754 tty_insert_flip_string(tty, icom_port->recv_buf + offset, count - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 }
756
757 icount = &icom_port->uart_port.icount;
758 icount->rx += count;
759
760 /* Break detect logic */
761 if ((status & SA_FLAGS_FRAME_ERROR)
Alan Cox33f0f882006-01-09 20:54:13 -0800762 && first == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 status &= ~SA_FLAGS_FRAME_ERROR;
764 status |= SA_FLAGS_BREAK_DET;
765 trace(icom_port, "BREAK_DET", 0);
766 }
767
Alan Cox33f0f882006-01-09 20:54:13 -0800768 flag = TTY_NORMAL;
769
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (status &
771 (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR |
772 SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) {
773
774 if (status & SA_FLAGS_BREAK_DET)
775 icount->brk++;
776 if (status & SA_FLAGS_PARITY_ERROR)
777 icount->parity++;
778 if (status & SA_FLAGS_FRAME_ERROR)
779 icount->frame++;
780 if (status & SA_FLAGS_OVERRUN)
781 icount->overrun++;
782
783 /*
784 * Now check to see if character should be
785 * ignored, and mask off conditions which
786 * should be ignored.
787 */
788 if (status & icom_port->ignore_status_mask) {
789 trace(icom_port, "IGNORE_CHAR", 0);
790 goto ignore_char;
791 }
792
793 status &= icom_port->read_status_mask;
794
795 if (status & SA_FLAGS_BREAK_DET) {
Alan Cox33f0f882006-01-09 20:54:13 -0800796 flag = TTY_BREAK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 } else if (status & SA_FLAGS_PARITY_ERROR) {
798 trace(icom_port, "PARITY_ERROR", 0);
Alan Cox33f0f882006-01-09 20:54:13 -0800799 flag = TTY_PARITY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 } else if (status & SA_FLAGS_FRAME_ERROR)
Alan Cox33f0f882006-01-09 20:54:13 -0800801 flag = TTY_FRAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 }
804
Alan Cox33f0f882006-01-09 20:54:13 -0800805 tty_insert_flip_char(tty, *(icom_port->recv_buf + offset + count - 1), flag);
806
807 if (status & SA_FLAGS_OVERRUN)
808 /*
809 * Overrun is special, since it's
810 * reported immediately, and doesn't
811 * affect the current character
812 */
813 tty_insert_flip_char(tty, 0, TTY_OVERRUN);
814ignore_char:
815 icom_port->statStg->rcv[rcv_buff].flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 icom_port->statStg->rcv[rcv_buff].leLength = 0;
817 icom_port->statStg->rcv[rcv_buff].WorkingLength =
818 (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
819
820 rcv_buff++;
821 if (rcv_buff == NUM_RBUFFS)
822 rcv_buff = 0;
823
824 status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
825 }
826 icom_port->next_rcv = rcv_buff;
827 tty_flip_buffer_push(tty);
828}
829
830static void process_interrupt(u16 port_int_reg,
831 struct icom_port *icom_port)
832{
833
834 spin_lock(&icom_port->uart_port.lock);
835 trace(icom_port, "INTERRUPT", port_int_reg);
836
837 if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED))
838 xmit_interrupt(port_int_reg, icom_port);
839
840 if (port_int_reg & INT_RCV_COMPLETED)
841 recv_interrupt(port_int_reg, icom_port);
842
843 spin_unlock(&icom_port->uart_port.lock);
844}
845
David Howells7d12e782006-10-05 14:55:46 +0100846static irqreturn_t icom_interrupt(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847{
848 void __iomem * int_reg;
849 u32 adapter_interrupts;
850 u16 port_int_reg;
851 struct icom_adapter *icom_adapter;
852 struct icom_port *icom_port;
853
854 /* find icom_port for this interrupt */
855 icom_adapter = (struct icom_adapter *) dev_id;
856
857 if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) {
858 int_reg = icom_adapter->base_addr + 0x8024;
859
860 adapter_interrupts = readl(int_reg);
861
862 if (adapter_interrupts & 0x00003FFF) {
863 /* port 2 interrupt, NOTE: for all ADAPTER_V2, port 2 will be active */
864 icom_port = &icom_adapter->port_info[2];
865 port_int_reg = (u16) adapter_interrupts;
866 process_interrupt(port_int_reg, icom_port);
867 check_modem_status(icom_port);
868 }
869 if (adapter_interrupts & 0x3FFF0000) {
870 /* port 3 interrupt */
871 icom_port = &icom_adapter->port_info[3];
872 if (icom_port->status == ICOM_PORT_ACTIVE) {
873 port_int_reg =
874 (u16) (adapter_interrupts >> 16);
875 process_interrupt(port_int_reg, icom_port);
876 check_modem_status(icom_port);
877 }
878 }
879
880 /* Clear out any pending interrupts */
881 writel(adapter_interrupts, int_reg);
882
883 int_reg = icom_adapter->base_addr + 0x8004;
884 } else {
885 int_reg = icom_adapter->base_addr + 0x4004;
886 }
887
888 adapter_interrupts = readl(int_reg);
889
890 if (adapter_interrupts & 0x00003FFF) {
891 /* port 0 interrupt, NOTE: for all adapters, port 0 will be active */
892 icom_port = &icom_adapter->port_info[0];
893 port_int_reg = (u16) adapter_interrupts;
894 process_interrupt(port_int_reg, icom_port);
895 check_modem_status(icom_port);
896 }
897 if (adapter_interrupts & 0x3FFF0000) {
898 /* port 1 interrupt */
899 icom_port = &icom_adapter->port_info[1];
900 if (icom_port->status == ICOM_PORT_ACTIVE) {
901 port_int_reg = (u16) (adapter_interrupts >> 16);
902 process_interrupt(port_int_reg, icom_port);
903 check_modem_status(icom_port);
904 }
905 }
906
907 /* Clear out any pending interrupts */
908 writel(adapter_interrupts, int_reg);
909
910 /* flush the write */
911 adapter_interrupts = readl(int_reg);
912
913 return IRQ_HANDLED;
914}
915
916/*
917 * ------------------------------------------------------------------
918 * Begin serial-core API
919 * ------------------------------------------------------------------
920 */
921static unsigned int icom_tx_empty(struct uart_port *port)
922{
923 int ret;
924 unsigned long flags;
925
926 spin_lock_irqsave(&port->lock, flags);
927 if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
928 SA_FLAGS_READY_TO_XMIT)
929 ret = TIOCSER_TEMT;
930 else
931 ret = 0;
932
933 spin_unlock_irqrestore(&port->lock, flags);
934 return ret;
935}
936
937static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl)
938{
939 unsigned char local_osr;
940
941 trace(ICOM_PORT, "SET_MODEM", 0);
942 local_osr = readb(&ICOM_PORT->dram->osr);
943
944 if (mctrl & TIOCM_RTS) {
945 trace(ICOM_PORT, "RAISE_RTS", 0);
946 local_osr |= ICOM_RTS;
947 } else {
948 trace(ICOM_PORT, "LOWER_RTS", 0);
949 local_osr &= ~ICOM_RTS;
950 }
951
952 if (mctrl & TIOCM_DTR) {
953 trace(ICOM_PORT, "RAISE_DTR", 0);
954 local_osr |= ICOM_DTR;
955 } else {
956 trace(ICOM_PORT, "LOWER_DTR", 0);
957 local_osr &= ~ICOM_DTR;
958 }
959
960 writeb(local_osr, &ICOM_PORT->dram->osr);
961}
962
963static unsigned int icom_get_mctrl(struct uart_port *port)
964{
965 unsigned char status;
966 unsigned int result;
967
968 trace(ICOM_PORT, "GET_MODEM", 0);
969
970 status = readb(&ICOM_PORT->dram->isr);
971
972 result = ((status & ICOM_DCD) ? TIOCM_CAR : 0)
973 | ((status & ICOM_RI) ? TIOCM_RNG : 0)
974 | ((status & ICOM_DSR) ? TIOCM_DSR : 0)
975 | ((status & ICOM_CTS) ? TIOCM_CTS : 0);
976 return result;
977}
978
Russell Kingb129a8c2005-08-31 10:12:14 +0100979static void icom_stop_tx(struct uart_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980{
981 unsigned char cmdReg;
982
Russell Kingb129a8c2005-08-31 10:12:14 +0100983 trace(ICOM_PORT, "STOP", 0);
984 cmdReg = readb(&ICOM_PORT->dram->CmdReg);
985 writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986}
987
Russell Kingb129a8c2005-08-31 10:12:14 +0100988static void icom_start_tx(struct uart_port *port)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989{
990 unsigned char cmdReg;
991
992 trace(ICOM_PORT, "START", 0);
993 cmdReg = readb(&ICOM_PORT->dram->CmdReg);
994 if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT)
995 writeb(cmdReg & ~CMD_HOLD_XMIT,
996 &ICOM_PORT->dram->CmdReg);
997
998 icom_write(port);
999}
1000
1001static void icom_send_xchar(struct uart_port *port, char ch)
1002{
1003 unsigned char xdata;
1004 int index;
1005 unsigned long flags;
1006
1007 trace(ICOM_PORT, "SEND_XCHAR", ch);
1008
1009 /* wait .1 sec to send char */
1010 for (index = 0; index < 10; index++) {
1011 spin_lock_irqsave(&port->lock, flags);
1012 xdata = readb(&ICOM_PORT->dram->xchar);
1013 if (xdata == 0x00) {
1014 trace(ICOM_PORT, "QUICK_WRITE", 0);
1015 writeb(ch, &ICOM_PORT->dram->xchar);
1016
1017 /* flush write operation */
1018 xdata = readb(&ICOM_PORT->dram->xchar);
1019 spin_unlock_irqrestore(&port->lock, flags);
1020 break;
1021 }
1022 spin_unlock_irqrestore(&port->lock, flags);
1023 msleep(10);
1024 }
1025}
1026
1027static void icom_stop_rx(struct uart_port *port)
1028{
1029 unsigned char cmdReg;
1030
1031 cmdReg = readb(&ICOM_PORT->dram->CmdReg);
1032 writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
1033}
1034
1035static void icom_enable_ms(struct uart_port *port)
1036{
1037 /* no-op */
1038}
1039
1040static void icom_break(struct uart_port *port, int break_state)
1041{
1042 unsigned char cmdReg;
1043 unsigned long flags;
1044
1045 spin_lock_irqsave(&port->lock, flags);
1046 trace(ICOM_PORT, "BREAK", 0);
1047 cmdReg = readb(&ICOM_PORT->dram->CmdReg);
1048 if (break_state == -1) {
1049 writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
1050 } else {
1051 writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
1052 }
1053 spin_unlock_irqrestore(&port->lock, flags);
1054}
1055
1056static int icom_open(struct uart_port *port)
1057{
1058 int retval;
1059
1060 kobject_get(&ICOM_PORT->adapter->kobj);
1061 retval = startup(ICOM_PORT);
1062
1063 if (retval) {
1064 kobject_put(&ICOM_PORT->adapter->kobj);
1065 trace(ICOM_PORT, "STARTUP_ERROR", 0);
1066 return retval;
1067 }
1068
1069 return 0;
1070}
1071
1072static void icom_close(struct uart_port *port)
1073{
1074 unsigned char cmdReg;
1075
1076 trace(ICOM_PORT, "CLOSE", 0);
1077
1078 /* stop receiver */
1079 cmdReg = readb(&ICOM_PORT->dram->CmdReg);
1080 writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE,
1081 &ICOM_PORT->dram->CmdReg);
1082
1083 shutdown(ICOM_PORT);
1084
1085 kobject_put(&ICOM_PORT->adapter->kobj);
1086}
1087
1088static void icom_set_termios(struct uart_port *port,
Alan Cox606d0992006-12-08 02:38:45 -08001089 struct ktermios *termios,
1090 struct ktermios *old_termios)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091{
1092 int baud;
1093 unsigned cflag, iflag;
1094 int bits;
1095 char new_config2;
1096 char new_config3 = 0;
1097 char tmp_byte;
1098 int index;
1099 int rcv_buff, xmit_buff;
1100 unsigned long offset;
1101 unsigned long flags;
1102
1103 spin_lock_irqsave(&port->lock, flags);
1104 trace(ICOM_PORT, "CHANGE_SPEED", 0);
1105
1106 cflag = termios->c_cflag;
1107 iflag = termios->c_iflag;
1108
1109 new_config2 = ICOM_ACFG_DRIVE1;
1110
1111 /* byte size and parity */
1112 switch (cflag & CSIZE) {
1113 case CS5: /* 5 bits/char */
1114 new_config2 |= ICOM_ACFG_5BPC;
1115 bits = 7;
1116 break;
1117 case CS6: /* 6 bits/char */
1118 new_config2 |= ICOM_ACFG_6BPC;
1119 bits = 8;
1120 break;
1121 case CS7: /* 7 bits/char */
1122 new_config2 |= ICOM_ACFG_7BPC;
1123 bits = 9;
1124 break;
1125 case CS8: /* 8 bits/char */
1126 new_config2 |= ICOM_ACFG_8BPC;
1127 bits = 10;
1128 break;
1129 default:
1130 bits = 10;
1131 break;
1132 }
1133 if (cflag & CSTOPB) {
1134 /* 2 stop bits */
1135 new_config2 |= ICOM_ACFG_2STOP_BIT;
1136 bits++;
1137 }
1138 if (cflag & PARENB) {
1139 /* parity bit enabled */
1140 new_config2 |= ICOM_ACFG_PARITY_ENAB;
1141 trace(ICOM_PORT, "PARENB", 0);
1142 bits++;
1143 }
1144 if (cflag & PARODD) {
1145 /* odd parity */
1146 new_config2 |= ICOM_ACFG_PARITY_ODD;
1147 trace(ICOM_PORT, "PARODD", 0);
1148 }
1149
1150 /* Determine divisor based on baud rate */
1151 baud = uart_get_baud_rate(port, termios, old_termios,
1152 icom_acfg_baud[0],
1153 icom_acfg_baud[BAUD_TABLE_LIMIT]);
1154 if (!baud)
1155 baud = 9600; /* B0 transition handled in rs_set_termios */
1156
1157 for (index = 0; index < BAUD_TABLE_LIMIT; index++) {
1158 if (icom_acfg_baud[index] == baud) {
1159 new_config3 = index;
1160 break;
1161 }
1162 }
1163
1164 uart_update_timeout(port, cflag, baud);
1165
1166 /* CTS flow control flag and modem status interrupts */
1167 tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
1168 if (cflag & CRTSCTS)
1169 tmp_byte |= HDLC_HDW_FLOW;
1170 else
1171 tmp_byte &= ~HDLC_HDW_FLOW;
1172 writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
1173
1174 /*
1175 * Set up parity check flag
1176 */
1177 ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;
1178 if (iflag & INPCK)
1179 ICOM_PORT->read_status_mask |=
1180 SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR;
1181
1182 if ((iflag & BRKINT) || (iflag & PARMRK))
1183 ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET;
1184
1185 /*
1186 * Characters to ignore
1187 */
1188 ICOM_PORT->ignore_status_mask = 0;
1189 if (iflag & IGNPAR)
1190 ICOM_PORT->ignore_status_mask |=
1191 SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR;
1192 if (iflag & IGNBRK) {
1193 ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET;
1194 /*
1195 * If we're ignore parity and break indicators, ignore
1196 * overruns too. (For real raw support).
1197 */
1198 if (iflag & IGNPAR)
1199 ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN;
1200 }
1201
1202 /*
1203 * !!! ignore all characters if CREAD is not set
1204 */
1205 if ((cflag & CREAD) == 0)
1206 ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE;
1207
1208 /* Turn off Receiver to prepare for reset */
1209 writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg);
1210
1211 for (index = 0; index < 10; index++) {
1212 if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) {
1213 break;
1214 }
1215 }
1216
1217 /* clear all current buffers of data */
1218 for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) {
1219 ICOM_PORT->statStg->rcv[rcv_buff].flags = 0;
1220 ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0;
1221 ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength =
1222 (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
1223 }
1224
1225 for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) {
1226 ICOM_PORT->statStg->xmit[xmit_buff].flags = 0;
1227 }
1228
1229 /* activate changes and start xmit and receiver here */
1230 /* Enable the receiver */
1231 writeb(new_config3, &(ICOM_PORT->dram->async_config3));
1232 writeb(new_config2, &(ICOM_PORT->dram->async_config2));
1233 tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
1234 tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL;
1235 writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
1236 writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer)); /* 0.5 seconds */
1237 writeb(0xFF, &(ICOM_PORT->dram->ier)); /* enable modem signal interrupts */
1238
1239 /* reset processor */
1240 writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg);
1241
1242 for (index = 0; index < 10; index++) {
1243 if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) {
1244 break;
1245 }
1246 }
1247
1248 /* Enable Transmitter and Reciever */
1249 offset =
1250 (unsigned long) &ICOM_PORT->statStg->rcv[0] -
1251 (unsigned long) ICOM_PORT->statStg;
1252 writel(ICOM_PORT->statStg_pci + offset,
1253 &ICOM_PORT->dram->RcvStatusAddr);
1254 ICOM_PORT->next_rcv = 0;
1255 ICOM_PORT->put_length = 0;
1256 *ICOM_PORT->xmitRestart = 0;
1257 writel(ICOM_PORT->xmitRestart_pci,
1258 &ICOM_PORT->dram->XmitStatusAddr);
1259 trace(ICOM_PORT, "XR_ENAB", 0);
1260 writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
1261
1262 spin_unlock_irqrestore(&port->lock, flags);
1263}
1264
1265static const char *icom_type(struct uart_port *port)
1266{
1267 return "icom";
1268}
1269
1270static void icom_release_port(struct uart_port *port)
1271{
1272}
1273
1274static int icom_request_port(struct uart_port *port)
1275{
1276 return 0;
1277}
1278
1279static void icom_config_port(struct uart_port *port, int flags)
1280{
1281 port->type = PORT_ICOM;
1282}
1283
1284static struct uart_ops icom_ops = {
1285 .tx_empty = icom_tx_empty,
1286 .set_mctrl = icom_set_mctrl,
1287 .get_mctrl = icom_get_mctrl,
1288 .stop_tx = icom_stop_tx,
1289 .start_tx = icom_start_tx,
1290 .send_xchar = icom_send_xchar,
1291 .stop_rx = icom_stop_rx,
1292 .enable_ms = icom_enable_ms,
1293 .break_ctl = icom_break,
1294 .startup = icom_open,
1295 .shutdown = icom_close,
1296 .set_termios = icom_set_termios,
1297 .type = icom_type,
1298 .release_port = icom_release_port,
1299 .request_port = icom_request_port,
1300 .config_port = icom_config_port,
1301};
1302
1303#define ICOM_CONSOLE NULL
1304
1305static struct uart_driver icom_uart_driver = {
1306 .owner = THIS_MODULE,
1307 .driver_name = ICOM_DRIVER_NAME,
1308 .dev_name = "ttyA",
1309 .major = ICOM_MAJOR,
1310 .minor = ICOM_MINOR_START,
1311 .nr = NR_PORTS,
1312 .cons = ICOM_CONSOLE,
1313};
1314
1315static int __devinit icom_init_ports(struct icom_adapter *icom_adapter)
1316{
1317 u32 subsystem_id = icom_adapter->subsystem_id;
1318 int retval = 0;
1319 int i;
1320 struct icom_port *icom_port;
1321
1322 if (icom_adapter->version == ADAPTER_V1) {
1323 icom_adapter->numb_ports = 2;
1324
1325 for (i = 0; i < 2; i++) {
1326 icom_port = &icom_adapter->port_info[i];
1327 icom_port->port = i;
1328 icom_port->status = ICOM_PORT_ACTIVE;
1329 icom_port->imbed_modem = ICOM_UNKNOWN;
1330 }
1331 } else {
1332 if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) {
1333 icom_adapter->numb_ports = 4;
1334
1335 for (i = 0; i < 4; i++) {
1336 icom_port = &icom_adapter->port_info[i];
1337
1338 icom_port->port = i;
1339 icom_port->status = ICOM_PORT_ACTIVE;
1340 icom_port->imbed_modem = ICOM_IMBED_MODEM;
1341 }
1342 } else {
1343 icom_adapter->numb_ports = 4;
1344
1345 icom_adapter->port_info[0].port = 0;
1346 icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE;
1347
1348 if (subsystem_id ==
1349 PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) {
1350 icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM;
1351 } else {
1352 icom_adapter->port_info[0].imbed_modem = ICOM_RVX;
1353 }
1354
1355 icom_adapter->port_info[1].status = ICOM_PORT_OFF;
1356
1357 icom_adapter->port_info[2].port = 2;
1358 icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE;
1359 icom_adapter->port_info[2].imbed_modem = ICOM_RVX;
1360 icom_adapter->port_info[3].status = ICOM_PORT_OFF;
1361 }
1362 }
1363
1364 return retval;
1365}
1366
1367static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num)
1368{
1369 if (icom_adapter->version == ADAPTER_V1) {
1370 icom_port->global_reg = icom_adapter->base_addr + 0x4000;
1371 icom_port->int_reg = icom_adapter->base_addr +
1372 0x4004 + 2 - 2 * port_num;
1373 } else {
1374 icom_port->global_reg = icom_adapter->base_addr + 0x8000;
1375 if (icom_port->port < 2)
1376 icom_port->int_reg = icom_adapter->base_addr +
1377 0x8004 + 2 - 2 * icom_port->port;
1378 else
1379 icom_port->int_reg = icom_adapter->base_addr +
1380 0x8024 + 2 - 2 * (icom_port->port - 2);
1381 }
1382}
Jiri Slaby98f85d32007-04-23 14:41:20 -07001383static int __devinit icom_load_ports(struct icom_adapter *icom_adapter)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384{
1385 struct icom_port *icom_port;
1386 int port_num;
1387 int retval;
1388
1389 for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) {
1390
1391 icom_port = &icom_adapter->port_info[port_num];
1392
1393 if (icom_port->status == ICOM_PORT_ACTIVE) {
1394 icom_port_active(icom_port, icom_adapter, port_num);
1395 icom_port->dram = icom_adapter->base_addr +
1396 0x2000 * icom_port->port;
1397
1398 icom_port->adapter = icom_adapter;
1399
1400 /* get port memory */
1401 if ((retval = get_port_memory(icom_port)) != 0) {
1402 dev_err(&icom_port->adapter->pci_dev->dev,
1403 "Memory allocation for port FAILED\n");
1404 }
1405 }
1406 }
1407 return 0;
1408}
1409
1410static int __devinit icom_alloc_adapter(struct icom_adapter
1411 **icom_adapter_ref)
1412{
1413 int adapter_count = 0;
1414 struct icom_adapter *icom_adapter;
1415 struct icom_adapter *cur_adapter_entry;
1416 struct list_head *tmp;
1417
1418 icom_adapter = (struct icom_adapter *)
Burman Yan8f31bb32007-02-14 00:33:07 -08001419 kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420
1421 if (!icom_adapter) {
1422 return -ENOMEM;
1423 }
1424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 list_for_each(tmp, &icom_adapter_head) {
1426 cur_adapter_entry =
1427 list_entry(tmp, struct icom_adapter,
1428 icom_adapter_entry);
1429 if (cur_adapter_entry->index != adapter_count) {
1430 break;
1431 }
1432 adapter_count++;
1433 }
1434
1435 icom_adapter->index = adapter_count;
1436 list_add_tail(&icom_adapter->icom_adapter_entry, tmp);
1437
1438 *icom_adapter_ref = icom_adapter;
1439 return 0;
1440}
1441
1442static void icom_free_adapter(struct icom_adapter *icom_adapter)
1443{
1444 list_del(&icom_adapter->icom_adapter_entry);
1445 kfree(icom_adapter);
1446}
1447
1448static void icom_remove_adapter(struct icom_adapter *icom_adapter)
1449{
1450 struct icom_port *icom_port;
1451 int index;
1452
1453 for (index = 0; index < icom_adapter->numb_ports; index++) {
1454 icom_port = &icom_adapter->port_info[index];
1455
1456 if (icom_port->status == ICOM_PORT_ACTIVE) {
1457 dev_info(&icom_adapter->pci_dev->dev,
1458 "Device removed\n");
1459
1460 uart_remove_one_port(&icom_uart_driver,
1461 &icom_port->uart_port);
1462
1463 /* be sure that DTR and RTS are dropped */
1464 writeb(0x00, &icom_port->dram->osr);
1465
1466 /* Wait 0.1 Sec for simple Init to complete */
1467 msleep(100);
1468
1469 /* Stop proccessor */
1470 stop_processor(icom_port);
1471
1472 free_port_memory(icom_port);
1473 }
1474 }
1475
Olaf Hering179fb0c2007-04-23 14:41:15 -07001476 free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 iounmap(icom_adapter->base_addr);
1478 icom_free_adapter(icom_adapter);
1479 pci_release_regions(icom_adapter->pci_dev);
1480}
1481
1482static void icom_kobj_release(struct kobject *kobj)
1483{
1484 struct icom_adapter *icom_adapter;
1485
1486 icom_adapter = to_icom_adapter(kobj);
1487 icom_remove_adapter(icom_adapter);
1488}
1489
1490static struct kobj_type icom_kobj_type = {
1491 .release = icom_kobj_release,
1492};
1493
1494static int __devinit icom_probe(struct pci_dev *dev,
1495 const struct pci_device_id *ent)
1496{
1497 int index;
1498 unsigned int command_reg;
1499 int retval;
1500 struct icom_adapter *icom_adapter;
1501 struct icom_port *icom_port;
1502
1503 retval = pci_enable_device(dev);
1504 if (retval) {
1505 dev_err(&dev->dev, "Device enable FAILED\n");
1506 return retval;
1507 }
1508
1509 if ( (retval = pci_request_regions(dev, "icom"))) {
Thomas Hisch87c18aa2006-12-12 19:20:35 +01001510 dev_err(&dev->dev, "pci_request_regions FAILED\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 pci_disable_device(dev);
1512 return retval;
1513 }
1514
1515 pci_set_master(dev);
1516
1517 if ( (retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg))) {
1518 dev_err(&dev->dev, "PCI Config read FAILED\n");
1519 return retval;
1520 }
1521
1522 pci_write_config_dword(dev, PCI_COMMAND,
1523 command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
1524 | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
1525
1526 if (ent->driver_data == ADAPTER_V1) {
1527 pci_write_config_dword(dev, 0x44, 0x8300830A);
1528 } else {
1529 pci_write_config_dword(dev, 0x44, 0x42004200);
1530 pci_write_config_dword(dev, 0x48, 0x42004200);
1531 }
1532
1533
1534 retval = icom_alloc_adapter(&icom_adapter);
1535 if (retval) {
1536 dev_err(&dev->dev, "icom_alloc_adapter FAILED\n");
1537 retval = -EIO;
1538 goto probe_exit0;
1539 }
1540
1541 icom_adapter->base_addr_pci = pci_resource_start(dev, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 icom_adapter->pci_dev = dev;
1543 icom_adapter->version = ent->driver_data;
1544 icom_adapter->subsystem_id = ent->subdevice;
1545
1546
1547 retval = icom_init_ports(icom_adapter);
1548 if (retval) {
1549 dev_err(&dev->dev, "Port configuration failed\n");
1550 goto probe_exit1;
1551 }
1552
1553 icom_adapter->base_addr = ioremap(icom_adapter->base_addr_pci,
1554 pci_resource_len(dev, 0));
1555
1556 if (!icom_adapter->base_addr)
1557 goto probe_exit1;
1558
1559 /* save off irq and request irq line */
1560 if ( (retval = request_irq(dev->irq, icom_interrupt,
Thomas Gleixner40663cc2006-07-01 19:29:43 -07001561 IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 (void *) icom_adapter))) {
1563 goto probe_exit2;
1564 }
1565
1566 retval = icom_load_ports(icom_adapter);
1567
1568 for (index = 0; index < icom_adapter->numb_ports; index++) {
1569 icom_port = &icom_adapter->port_info[index];
1570
1571 if (icom_port->status == ICOM_PORT_ACTIVE) {
Olaf Hering179fb0c2007-04-23 14:41:15 -07001572 icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 icom_port->uart_port.type = PORT_ICOM;
1574 icom_port->uart_port.iotype = UPIO_MEM;
1575 icom_port->uart_port.membase =
1576 (char *) icom_adapter->base_addr_pci;
1577 icom_port->uart_port.fifosize = 16;
1578 icom_port->uart_port.ops = &icom_ops;
1579 icom_port->uart_port.line =
1580 icom_port->port + icom_adapter->index * 4;
1581 if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) {
1582 icom_port->status = ICOM_PORT_OFF;
1583 dev_err(&dev->dev, "Device add failed\n");
1584 } else
1585 dev_info(&dev->dev, "Device added\n");
1586 }
1587 }
1588
1589 kobject_init(&icom_adapter->kobj);
1590 icom_adapter->kobj.ktype = &icom_kobj_type;
1591 return 0;
1592
1593probe_exit2:
1594 iounmap(icom_adapter->base_addr);
1595probe_exit1:
1596 icom_free_adapter(icom_adapter);
1597
1598probe_exit0:
1599 pci_release_regions(dev);
1600 pci_disable_device(dev);
1601
1602 return retval;
1603
1604
1605}
1606
1607static void __devexit icom_remove(struct pci_dev *dev)
1608{
1609 struct icom_adapter *icom_adapter;
1610 struct list_head *tmp;
1611
1612 list_for_each(tmp, &icom_adapter_head) {
1613 icom_adapter = list_entry(tmp, struct icom_adapter,
1614 icom_adapter_entry);
1615 if (icom_adapter->pci_dev == dev) {
1616 kobject_put(&icom_adapter->kobj);
1617 return;
1618 }
1619 }
1620
1621 dev_err(&dev->dev, "Unable to find device to remove\n");
1622}
1623
1624static struct pci_driver icom_pci_driver = {
1625 .name = ICOM_DRIVER_NAME,
1626 .id_table = icom_pci_table,
1627 .probe = icom_probe,
1628 .remove = __devexit_p(icom_remove),
1629};
1630
1631static int __init icom_init(void)
1632{
1633 int ret;
1634
1635 spin_lock_init(&icom_lock);
1636
1637 ret = uart_register_driver(&icom_uart_driver);
1638 if (ret)
1639 return ret;
1640
1641 ret = pci_register_driver(&icom_pci_driver);
1642
1643 if (ret < 0)
1644 uart_unregister_driver(&icom_uart_driver);
1645
1646 return ret;
1647}
1648
1649static void __exit icom_exit(void)
1650{
1651 pci_unregister_driver(&icom_pci_driver);
1652 uart_unregister_driver(&icom_uart_driver);
1653}
1654
1655module_init(icom_init);
1656module_exit(icom_exit);
1657
1658#ifdef ICOM_TRACE
1659static inline void trace(struct icom_port *icom_port, char *trace_pt,
1660 unsigned long trace_data)
1661{
1662 dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
1663 icom_port->port, trace_pt, trace_data);
1664}
1665#endif
1666
1667MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
1668MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
1669MODULE_SUPPORTED_DEVICE
1670 ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters");
1671MODULE_LICENSE("GPL");
1672