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