12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661 |
- /*
- * icom.c
- *
- * Copyright (C) 2001 IBM Corporation. All rights reserved.
- *
- * Serial device driver.
- *
- * Based on code from serial.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
- #define SERIAL_DO_RESTART
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/errno.h>
- #include <linux/signal.h>
- #include <linux/timer.h>
- #include <linux/interrupt.h>
- #include <linux/tty.h>
- #include <linux/termios.h>
- #include <linux/fs.h>
- #include <linux/tty_flip.h>
- #include <linux/serial.h>
- #include <linux/serial_reg.h>
- #include <linux/major.h>
- #include <linux/string.h>
- #include <linux/fcntl.h>
- #include <linux/ptrace.h>
- #include <linux/ioport.h>
- #include <linux/mm.h>
- #include <linux/slab.h>
- #include <linux/init.h>
- #include <linux/delay.h>
- #include <linux/pci.h>
- #include <linux/vmalloc.h>
- #include <linux/smp.h>
- #include <linux/spinlock.h>
- #include <linux/kref.h>
- #include <linux/firmware.h>
- #include <linux/bitops.h>
- #include <asm/io.h>
- #include <asm/irq.h>
- #include <asm/uaccess.h>
- #include "icom.h"
- /*#define ICOM_TRACE enable port trace capabilities */
- #define ICOM_DRIVER_NAME "icom"
- #define ICOM_VERSION_STR "1.3.1"
- #define NR_PORTS 128
- #define ICOM_PORT ((struct icom_port *)port)
- #define to_icom_adapter(d) container_of(d, struct icom_adapter, kref)
- static const struct pci_device_id icom_pci_table[] = {
- {
- .vendor = PCI_VENDOR_ID_IBM,
- .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = ADAPTER_V1,
- },
- {
- .vendor = PCI_VENDOR_ID_IBM,
- .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
- .subvendor = PCI_VENDOR_ID_IBM,
- .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX,
- .driver_data = ADAPTER_V2,
- },
- {
- .vendor = PCI_VENDOR_ID_IBM,
- .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
- .subvendor = PCI_VENDOR_ID_IBM,
- .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM,
- .driver_data = ADAPTER_V2,
- },
- {
- .vendor = PCI_VENDOR_ID_IBM,
- .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
- .subvendor = PCI_VENDOR_ID_IBM,
- .subdevice = PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL,
- .driver_data = ADAPTER_V2,
- },
- {
- .vendor = PCI_VENDOR_ID_IBM,
- .device = PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2,
- .subvendor = PCI_VENDOR_ID_IBM,
- .subdevice = PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE,
- .driver_data = ADAPTER_V2,
- },
- {}
- };
- static struct lookup_proc_table start_proc[4] = {
- {NULL, ICOM_CONTROL_START_A},
- {NULL, ICOM_CONTROL_START_B},
- {NULL, ICOM_CONTROL_START_C},
- {NULL, ICOM_CONTROL_START_D}
- };
- static struct lookup_proc_table stop_proc[4] = {
- {NULL, ICOM_CONTROL_STOP_A},
- {NULL, ICOM_CONTROL_STOP_B},
- {NULL, ICOM_CONTROL_STOP_C},
- {NULL, ICOM_CONTROL_STOP_D}
- };
- static struct lookup_int_table int_mask_tbl[4] = {
- {NULL, ICOM_INT_MASK_PRC_A},
- {NULL, ICOM_INT_MASK_PRC_B},
- {NULL, ICOM_INT_MASK_PRC_C},
- {NULL, ICOM_INT_MASK_PRC_D},
- };
- MODULE_DEVICE_TABLE(pci, icom_pci_table);
- static LIST_HEAD(icom_adapter_head);
- /* spinlock for adapter initialization and changing adapter operations */
- static spinlock_t icom_lock;
- #ifdef ICOM_TRACE
- static inline void trace(struct icom_port *icom_port, char *trace_pt,
- unsigned long trace_data)
- {
- dev_info(&icom_port->adapter->pci_dev->dev, ":%d:%s - %lx\n",
- icom_port->port, trace_pt, trace_data);
- }
- #else
- static inline void trace(struct icom_port *icom_port, char *trace_pt, unsigned long trace_data) {};
- #endif
- static void icom_kref_release(struct kref *kref);
- static void free_port_memory(struct icom_port *icom_port)
- {
- struct pci_dev *dev = icom_port->adapter->pci_dev;
- trace(icom_port, "RET_PORT_MEM", 0);
- if (icom_port->recv_buf) {
- pci_free_consistent(dev, 4096, icom_port->recv_buf,
- icom_port->recv_buf_pci);
- icom_port->recv_buf = NULL;
- }
- if (icom_port->xmit_buf) {
- pci_free_consistent(dev, 4096, icom_port->xmit_buf,
- icom_port->xmit_buf_pci);
- icom_port->xmit_buf = NULL;
- }
- if (icom_port->statStg) {
- pci_free_consistent(dev, 4096, icom_port->statStg,
- icom_port->statStg_pci);
- icom_port->statStg = NULL;
- }
- if (icom_port->xmitRestart) {
- pci_free_consistent(dev, 4096, icom_port->xmitRestart,
- icom_port->xmitRestart_pci);
- icom_port->xmitRestart = NULL;
- }
- }
- static int get_port_memory(struct icom_port *icom_port)
- {
- int index;
- unsigned long stgAddr;
- unsigned long startStgAddr;
- unsigned long offset;
- struct pci_dev *dev = icom_port->adapter->pci_dev;
- icom_port->xmit_buf =
- pci_alloc_consistent(dev, 4096, &icom_port->xmit_buf_pci);
- if (!icom_port->xmit_buf) {
- dev_err(&dev->dev, "Can not allocate Transmit buffer\n");
- return -ENOMEM;
- }
- trace(icom_port, "GET_PORT_MEM",
- (unsigned long) icom_port->xmit_buf);
- icom_port->recv_buf =
- pci_alloc_consistent(dev, 4096, &icom_port->recv_buf_pci);
- if (!icom_port->recv_buf) {
- dev_err(&dev->dev, "Can not allocate Receive buffer\n");
- free_port_memory(icom_port);
- return -ENOMEM;
- }
- trace(icom_port, "GET_PORT_MEM",
- (unsigned long) icom_port->recv_buf);
- icom_port->statStg =
- pci_alloc_consistent(dev, 4096, &icom_port->statStg_pci);
- if (!icom_port->statStg) {
- dev_err(&dev->dev, "Can not allocate Status buffer\n");
- free_port_memory(icom_port);
- return -ENOMEM;
- }
- trace(icom_port, "GET_PORT_MEM",
- (unsigned long) icom_port->statStg);
- icom_port->xmitRestart =
- pci_alloc_consistent(dev, 4096, &icom_port->xmitRestart_pci);
- if (!icom_port->xmitRestart) {
- dev_err(&dev->dev,
- "Can not allocate xmit Restart buffer\n");
- free_port_memory(icom_port);
- return -ENOMEM;
- }
- memset(icom_port->statStg, 0, 4096);
- /* FODs: Frame Out Descriptor Queue, this is a FIFO queue that
- indicates that frames are to be transmitted
- */
- stgAddr = (unsigned long) icom_port->statStg;
- for (index = 0; index < NUM_XBUFFS; index++) {
- trace(icom_port, "FOD_ADDR", stgAddr);
- stgAddr = stgAddr + sizeof(icom_port->statStg->xmit[0]);
- if (index < (NUM_XBUFFS - 1)) {
- memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
- icom_port->statStg->xmit[index].leLengthASD =
- (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
- trace(icom_port, "FOD_ADDR", stgAddr);
- trace(icom_port, "FOD_XBUFF",
- (unsigned long) icom_port->xmit_buf);
- icom_port->statStg->xmit[index].leBuffer =
- cpu_to_le32(icom_port->xmit_buf_pci);
- } else if (index == (NUM_XBUFFS - 1)) {
- memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
- icom_port->statStg->xmit[index].leLengthASD =
- (unsigned short int) cpu_to_le16(XMIT_BUFF_SZ);
- trace(icom_port, "FOD_XBUFF",
- (unsigned long) icom_port->xmit_buf);
- icom_port->statStg->xmit[index].leBuffer =
- cpu_to_le32(icom_port->xmit_buf_pci);
- } else {
- memset(&icom_port->statStg->xmit[index], 0, sizeof(struct xmit_status_area));
- }
- }
- /* FIDs */
- startStgAddr = stgAddr;
- /* fill in every entry, even if no buffer */
- for (index = 0; index < NUM_RBUFFS; index++) {
- trace(icom_port, "FID_ADDR", stgAddr);
- stgAddr = stgAddr + sizeof(icom_port->statStg->rcv[0]);
- icom_port->statStg->rcv[index].leLength = 0;
- icom_port->statStg->rcv[index].WorkingLength =
- (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
- if (index < (NUM_RBUFFS - 1) ) {
- offset = stgAddr - (unsigned long) icom_port->statStg;
- icom_port->statStg->rcv[index].leNext =
- cpu_to_le32(icom_port-> statStg_pci + offset);
- trace(icom_port, "FID_RBUFF",
- (unsigned long) icom_port->recv_buf);
- icom_port->statStg->rcv[index].leBuffer =
- cpu_to_le32(icom_port->recv_buf_pci);
- } else if (index == (NUM_RBUFFS -1) ) {
- offset = startStgAddr - (unsigned long) icom_port->statStg;
- icom_port->statStg->rcv[index].leNext =
- cpu_to_le32(icom_port-> statStg_pci + offset);
- trace(icom_port, "FID_RBUFF",
- (unsigned long) icom_port->recv_buf + 2048);
- icom_port->statStg->rcv[index].leBuffer =
- cpu_to_le32(icom_port->recv_buf_pci + 2048);
- } else {
- icom_port->statStg->rcv[index].leNext = 0;
- icom_port->statStg->rcv[index].leBuffer = 0;
- }
- }
- return 0;
- }
- static void stop_processor(struct icom_port *icom_port)
- {
- unsigned long temp;
- unsigned long flags;
- int port;
- spin_lock_irqsave(&icom_lock, flags);
- port = icom_port->port;
- if (port >= ARRAY_SIZE(stop_proc)) {
- dev_err(&icom_port->adapter->pci_dev->dev,
- "Invalid port assignment\n");
- goto unlock;
- }
- if (port == 0 || port == 1)
- stop_proc[port].global_control_reg = &icom_port->global_reg->control;
- else
- stop_proc[port].global_control_reg = &icom_port->global_reg->control_2;
- temp = readl(stop_proc[port].global_control_reg);
- temp = (temp & ~start_proc[port].processor_id) | stop_proc[port].processor_id;
- writel(temp, stop_proc[port].global_control_reg);
- /* write flush */
- readl(stop_proc[port].global_control_reg);
- unlock:
- spin_unlock_irqrestore(&icom_lock, flags);
- }
- static void start_processor(struct icom_port *icom_port)
- {
- unsigned long temp;
- unsigned long flags;
- int port;
- spin_lock_irqsave(&icom_lock, flags);
- port = icom_port->port;
- if (port >= ARRAY_SIZE(start_proc)) {
- dev_err(&icom_port->adapter->pci_dev->dev,
- "Invalid port assignment\n");
- goto unlock;
- }
- if (port == 0 || port == 1)
- start_proc[port].global_control_reg = &icom_port->global_reg->control;
- else
- start_proc[port].global_control_reg = &icom_port->global_reg->control_2;
- temp = readl(start_proc[port].global_control_reg);
- temp = (temp & ~stop_proc[port].processor_id) | start_proc[port].processor_id;
- writel(temp, start_proc[port].global_control_reg);
- /* write flush */
- readl(start_proc[port].global_control_reg);
- unlock:
- spin_unlock_irqrestore(&icom_lock, flags);
- }
- static void load_code(struct icom_port *icom_port)
- {
- const struct firmware *fw;
- char __iomem *iram_ptr;
- int index;
- int status = 0;
- void __iomem *dram_ptr = icom_port->dram;
- dma_addr_t temp_pci;
- unsigned char *new_page = NULL;
- unsigned char cable_id = NO_CABLE;
- struct pci_dev *dev = icom_port->adapter->pci_dev;
- /* Clear out any pending interrupts */
- writew(0x3FFF, icom_port->int_reg);
- trace(icom_port, "CLEAR_INTERRUPTS", 0);
- /* Stop processor */
- stop_processor(icom_port);
- /* Zero out DRAM */
- memset_io(dram_ptr, 0, 512);
- /* Load Call Setup into Adapter */
- if (reject_firmware(&fw, "/*(DEBLOBBED)*/", &dev->dev) < 0) {
- dev_err(&dev->dev,"Unable to load /*(DEBLOBBED)*/ firmware image\n");
- status = -1;
- goto load_code_exit;
- }
- if (fw->size > ICOM_DCE_IRAM_OFFSET) {
- dev_err(&dev->dev, "Invalid firmware image for /*(DEBLOBBED)*/ found.\n");
- release_firmware(fw);
- status = -1;
- goto load_code_exit;
- }
- iram_ptr = (char __iomem *)icom_port->dram + ICOM_IRAM_OFFSET;
- for (index = 0; index < fw->size; index++)
- writeb(fw->data[index], &iram_ptr[index]);
- release_firmware(fw);
- /* Load Resident DCE portion of Adapter */
- if (reject_firmware(&fw, "/*(DEBLOBBED)*/", &dev->dev) < 0) {
- dev_err(&dev->dev,"Unable to load /*(DEBLOBBED)*/ firmware image\n");
- status = -1;
- goto load_code_exit;
- }
- if (fw->size > ICOM_IRAM_SIZE) {
- dev_err(&dev->dev, "Invalid firmware image for /*(DEBLOBBED)*/ found.\n");
- release_firmware(fw);
- status = -1;
- goto load_code_exit;
- }
- iram_ptr = (char __iomem *) icom_port->dram + ICOM_IRAM_OFFSET;
- for (index = ICOM_DCE_IRAM_OFFSET; index < fw->size; index++)
- writeb(fw->data[index], &iram_ptr[index]);
- release_firmware(fw);
- /* Set Hardware level */
- if (icom_port->adapter->version == ADAPTER_V2)
- writeb(V2_HARDWARE, &(icom_port->dram->misc_flags));
- /* Start the processor in Adapter */
- start_processor(icom_port);
- writeb((HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL),
- &(icom_port->dram->HDLCConfigReg));
- writeb(0x04, &(icom_port->dram->FlagFillIdleTimer)); /* 0.5 seconds */
- writeb(0x00, &(icom_port->dram->CmdReg));
- writeb(0x10, &(icom_port->dram->async_config3));
- writeb((ICOM_ACFG_DRIVE1 | ICOM_ACFG_NO_PARITY | ICOM_ACFG_8BPC |
- ICOM_ACFG_1STOP_BIT), &(icom_port->dram->async_config2));
- /*Set up data in icom DRAM to indicate where personality
- *code is located and its length.
- */
- new_page = pci_alloc_consistent(dev, 4096, &temp_pci);
- if (!new_page) {
- dev_err(&dev->dev, "Can not allocate DMA buffer\n");
- status = -1;
- goto load_code_exit;
- }
- if (reject_firmware(&fw, "/*(DEBLOBBED)*/", &dev->dev) < 0) {
- dev_err(&dev->dev,"Unable to load /*(DEBLOBBED)*/ firmware image\n");
- status = -1;
- goto load_code_exit;
- }
- if (fw->size > ICOM_DCE_IRAM_OFFSET) {
- dev_err(&dev->dev, "Invalid firmware image for /*(DEBLOBBED)*/ found.\n");
- release_firmware(fw);
- status = -1;
- goto load_code_exit;
- }
- for (index = 0; index < fw->size; index++)
- new_page[index] = fw->data[index];
- writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length);
- writel(temp_pci, &icom_port->dram->mac_load_addr);
- release_firmware(fw);
- /*Setting the syncReg to 0x80 causes adapter to start downloading
- the personality code into adapter instruction RAM.
- Once code is loaded, it will begin executing and, based on
- information provided above, will start DMAing data from
- shared memory to adapter DRAM.
- */
- /* the wait loop below verifies this write operation has been done
- and processed
- */
- writeb(START_DOWNLOAD, &icom_port->dram->sync);
- /* Wait max 1 Sec for data download and processor to start */
- for (index = 0; index < 10; index++) {
- msleep(100);
- if (readb(&icom_port->dram->misc_flags) & ICOM_HDW_ACTIVE)
- break;
- }
- if (index == 10)
- status = -1;
- /*
- * check Cable ID
- */
- cable_id = readb(&icom_port->dram->cable_id);
- if (cable_id & ICOM_CABLE_ID_VALID) {
- /* Get cable ID into the lower 4 bits (standard form) */
- cable_id = (cable_id & ICOM_CABLE_ID_MASK) >> 4;
- icom_port->cable_id = cable_id;
- } else {
- dev_err(&dev->dev,"Invalid or no cable attached\n");
- icom_port->cable_id = NO_CABLE;
- }
- load_code_exit:
- if (status != 0) {
- /* Clear out any pending interrupts */
- writew(0x3FFF, icom_port->int_reg);
- /* Turn off port */
- writeb(ICOM_DISABLE, &(icom_port->dram->disable));
- /* Stop processor */
- stop_processor(icom_port);
- dev_err(&icom_port->adapter->pci_dev->dev,"Port not operational\n");
- }
- if (new_page != NULL)
- pci_free_consistent(dev, 4096, new_page, temp_pci);
- }
- static int startup(struct icom_port *icom_port)
- {
- unsigned long temp;
- unsigned char cable_id, raw_cable_id;
- unsigned long flags;
- int port;
- trace(icom_port, "STARTUP", 0);
- if (!icom_port->dram) {
- /* should NEVER be NULL */
- dev_err(&icom_port->adapter->pci_dev->dev,
- "Unusable Port, port configuration missing\n");
- return -ENODEV;
- }
- /*
- * check Cable ID
- */
- raw_cable_id = readb(&icom_port->dram->cable_id);
- trace(icom_port, "CABLE_ID", raw_cable_id);
- /* Get cable ID into the lower 4 bits (standard form) */
- cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
- /* Check for valid Cable ID */
- if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
- (cable_id != icom_port->cable_id)) {
- /* reload adapter code, pick up any potential changes in cable id */
- load_code(icom_port);
- /* still no sign of cable, error out */
- raw_cable_id = readb(&icom_port->dram->cable_id);
- cable_id = (raw_cable_id & ICOM_CABLE_ID_MASK) >> 4;
- if (!(raw_cable_id & ICOM_CABLE_ID_VALID) ||
- (icom_port->cable_id == NO_CABLE))
- return -EIO;
- }
- /*
- * Finally, clear and enable interrupts
- */
- spin_lock_irqsave(&icom_lock, flags);
- port = icom_port->port;
- if (port >= ARRAY_SIZE(int_mask_tbl)) {
- dev_err(&icom_port->adapter->pci_dev->dev,
- "Invalid port assignment\n");
- goto unlock;
- }
- if (port == 0 || port == 1)
- int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
- else
- int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
- if (port == 0 || port == 2)
- writew(0x00FF, icom_port->int_reg);
- else
- writew(0x3F00, icom_port->int_reg);
- temp = readl(int_mask_tbl[port].global_int_mask);
- writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
- /* write flush */
- readl(int_mask_tbl[port].global_int_mask);
- unlock:
- spin_unlock_irqrestore(&icom_lock, flags);
- return 0;
- }
- static void shutdown(struct icom_port *icom_port)
- {
- unsigned long temp;
- unsigned char cmdReg;
- unsigned long flags;
- int port;
- spin_lock_irqsave(&icom_lock, flags);
- trace(icom_port, "SHUTDOWN", 0);
- /*
- * disable all interrupts
- */
- port = icom_port->port;
- if (port >= ARRAY_SIZE(int_mask_tbl)) {
- dev_err(&icom_port->adapter->pci_dev->dev,
- "Invalid port assignment\n");
- goto unlock;
- }
- if (port == 0 || port == 1)
- int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;
- else
- int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;
- temp = readl(int_mask_tbl[port].global_int_mask);
- writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);
- /* write flush */
- readl(int_mask_tbl[port].global_int_mask);
- unlock:
- spin_unlock_irqrestore(&icom_lock, flags);
- /*
- * disable break condition
- */
- cmdReg = readb(&icom_port->dram->CmdReg);
- if (cmdReg & CMD_SND_BREAK) {
- writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);
- }
- }
- static int icom_write(struct uart_port *port)
- {
- unsigned long data_count;
- unsigned char cmdReg;
- unsigned long offset;
- int temp_tail = port->state->xmit.tail;
- trace(ICOM_PORT, "WRITE", 0);
- if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
- SA_FLAGS_READY_TO_XMIT) {
- trace(ICOM_PORT, "WRITE_FULL", 0);
- return 0;
- }
- data_count = 0;
- while ((port->state->xmit.head != temp_tail) &&
- (data_count <= XMIT_BUFF_SZ)) {
- ICOM_PORT->xmit_buf[data_count++] =
- port->state->xmit.buf[temp_tail];
- temp_tail++;
- temp_tail &= (UART_XMIT_SIZE - 1);
- }
- if (data_count) {
- ICOM_PORT->statStg->xmit[0].flags =
- cpu_to_le16(SA_FLAGS_READY_TO_XMIT);
- ICOM_PORT->statStg->xmit[0].leLength =
- cpu_to_le16(data_count);
- offset =
- (unsigned long) &ICOM_PORT->statStg->xmit[0] -
- (unsigned long) ICOM_PORT->statStg;
- *ICOM_PORT->xmitRestart =
- cpu_to_le32(ICOM_PORT->statStg_pci + offset);
- cmdReg = readb(&ICOM_PORT->dram->CmdReg);
- writeb(cmdReg | CMD_XMIT_RCV_ENABLE,
- &ICOM_PORT->dram->CmdReg);
- writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd);
- trace(ICOM_PORT, "WRITE_START", data_count);
- /* write flush */
- readb(&ICOM_PORT->dram->StartXmitCmd);
- }
- return data_count;
- }
- static inline void check_modem_status(struct icom_port *icom_port)
- {
- static char old_status = 0;
- char delta_status;
- unsigned char status;
- spin_lock(&icom_port->uart_port.lock);
- /*modem input register */
- status = readb(&icom_port->dram->isr);
- trace(icom_port, "CHECK_MODEM", status);
- delta_status = status ^ old_status;
- if (delta_status) {
- if (delta_status & ICOM_RI)
- icom_port->uart_port.icount.rng++;
- if (delta_status & ICOM_DSR)
- icom_port->uart_port.icount.dsr++;
- if (delta_status & ICOM_DCD)
- uart_handle_dcd_change(&icom_port->uart_port,
- delta_status & ICOM_DCD);
- if (delta_status & ICOM_CTS)
- uart_handle_cts_change(&icom_port->uart_port,
- delta_status & ICOM_CTS);
- wake_up_interruptible(&icom_port->uart_port.state->
- port.delta_msr_wait);
- old_status = status;
- }
- spin_unlock(&icom_port->uart_port.lock);
- }
- static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port)
- {
- unsigned short int count;
- int i;
- if (port_int_reg & (INT_XMIT_COMPLETED)) {
- trace(icom_port, "XMIT_COMPLETE", 0);
- /* clear buffer in use bit */
- icom_port->statStg->xmit[0].flags &=
- cpu_to_le16(~SA_FLAGS_READY_TO_XMIT);
- count = (unsigned short int)
- cpu_to_le16(icom_port->statStg->xmit[0].leLength);
- icom_port->uart_port.icount.tx += count;
- for (i=0; i<count &&
- !uart_circ_empty(&icom_port->uart_port.state->xmit); i++) {
- icom_port->uart_port.state->xmit.tail++;
- icom_port->uart_port.state->xmit.tail &=
- (UART_XMIT_SIZE - 1);
- }
- if (!icom_write(&icom_port->uart_port))
- /* activate write queue */
- uart_write_wakeup(&icom_port->uart_port);
- } else
- trace(icom_port, "XMIT_DISABLED", 0);
- }
- static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port)
- {
- short int count, rcv_buff;
- struct tty_port *port = &icom_port->uart_port.state->port;
- unsigned short int status;
- struct uart_icount *icount;
- unsigned long offset;
- unsigned char flag;
- trace(icom_port, "RCV_COMPLETE", 0);
- rcv_buff = icom_port->next_rcv;
- status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
- while (status & SA_FL_RCV_DONE) {
- int first = -1;
- trace(icom_port, "FID_STATUS", status);
- count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength);
- trace(icom_port, "RCV_COUNT", count);
- trace(icom_port, "REAL_COUNT", count);
- offset =
- cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) -
- icom_port->recv_buf_pci;
- /* Block copy all but the last byte as this may have status */
- if (count > 0) {
- first = icom_port->recv_buf[offset];
- tty_insert_flip_string(port, icom_port->recv_buf + offset, count - 1);
- }
- icount = &icom_port->uart_port.icount;
- icount->rx += count;
- /* Break detect logic */
- if ((status & SA_FLAGS_FRAME_ERROR)
- && first == 0) {
- status &= ~SA_FLAGS_FRAME_ERROR;
- status |= SA_FLAGS_BREAK_DET;
- trace(icom_port, "BREAK_DET", 0);
- }
- flag = TTY_NORMAL;
- if (status &
- (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR |
- SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) {
- if (status & SA_FLAGS_BREAK_DET)
- icount->brk++;
- if (status & SA_FLAGS_PARITY_ERROR)
- icount->parity++;
- if (status & SA_FLAGS_FRAME_ERROR)
- icount->frame++;
- if (status & SA_FLAGS_OVERRUN)
- icount->overrun++;
- /*
- * Now check to see if character should be
- * ignored, and mask off conditions which
- * should be ignored.
- */
- if (status & icom_port->ignore_status_mask) {
- trace(icom_port, "IGNORE_CHAR", 0);
- goto ignore_char;
- }
- status &= icom_port->read_status_mask;
- if (status & SA_FLAGS_BREAK_DET) {
- flag = TTY_BREAK;
- } else if (status & SA_FLAGS_PARITY_ERROR) {
- trace(icom_port, "PARITY_ERROR", 0);
- flag = TTY_PARITY;
- } else if (status & SA_FLAGS_FRAME_ERROR)
- flag = TTY_FRAME;
- }
- tty_insert_flip_char(port, *(icom_port->recv_buf + offset + count - 1), flag);
- if (status & SA_FLAGS_OVERRUN)
- /*
- * Overrun is special, since it's
- * reported immediately, and doesn't
- * affect the current character
- */
- tty_insert_flip_char(port, 0, TTY_OVERRUN);
- ignore_char:
- icom_port->statStg->rcv[rcv_buff].flags = 0;
- icom_port->statStg->rcv[rcv_buff].leLength = 0;
- icom_port->statStg->rcv[rcv_buff].WorkingLength =
- (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
- rcv_buff++;
- if (rcv_buff == NUM_RBUFFS)
- rcv_buff = 0;
- status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);
- }
- icom_port->next_rcv = rcv_buff;
- spin_unlock(&icom_port->uart_port.lock);
- tty_flip_buffer_push(port);
- spin_lock(&icom_port->uart_port.lock);
- }
- static void process_interrupt(u16 port_int_reg,
- struct icom_port *icom_port)
- {
- spin_lock(&icom_port->uart_port.lock);
- trace(icom_port, "INTERRUPT", port_int_reg);
- if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED))
- xmit_interrupt(port_int_reg, icom_port);
- if (port_int_reg & INT_RCV_COMPLETED)
- recv_interrupt(port_int_reg, icom_port);
- spin_unlock(&icom_port->uart_port.lock);
- }
- static irqreturn_t icom_interrupt(int irq, void *dev_id)
- {
- void __iomem * int_reg;
- u32 adapter_interrupts;
- u16 port_int_reg;
- struct icom_adapter *icom_adapter;
- struct icom_port *icom_port;
- /* find icom_port for this interrupt */
- icom_adapter = (struct icom_adapter *) dev_id;
- if (icom_adapter->version == ADAPTER_V2) {
- int_reg = icom_adapter->base_addr + 0x8024;
- adapter_interrupts = readl(int_reg);
- if (adapter_interrupts & 0x00003FFF) {
- /* port 2 interrupt, NOTE: for all ADAPTER_V2, port 2 will be active */
- icom_port = &icom_adapter->port_info[2];
- port_int_reg = (u16) adapter_interrupts;
- process_interrupt(port_int_reg, icom_port);
- check_modem_status(icom_port);
- }
- if (adapter_interrupts & 0x3FFF0000) {
- /* port 3 interrupt */
- icom_port = &icom_adapter->port_info[3];
- if (icom_port->status == ICOM_PORT_ACTIVE) {
- port_int_reg =
- (u16) (adapter_interrupts >> 16);
- process_interrupt(port_int_reg, icom_port);
- check_modem_status(icom_port);
- }
- }
- /* Clear out any pending interrupts */
- writel(adapter_interrupts, int_reg);
- int_reg = icom_adapter->base_addr + 0x8004;
- } else {
- int_reg = icom_adapter->base_addr + 0x4004;
- }
- adapter_interrupts = readl(int_reg);
- if (adapter_interrupts & 0x00003FFF) {
- /* port 0 interrupt, NOTE: for all adapters, port 0 will be active */
- icom_port = &icom_adapter->port_info[0];
- port_int_reg = (u16) adapter_interrupts;
- process_interrupt(port_int_reg, icom_port);
- check_modem_status(icom_port);
- }
- if (adapter_interrupts & 0x3FFF0000) {
- /* port 1 interrupt */
- icom_port = &icom_adapter->port_info[1];
- if (icom_port->status == ICOM_PORT_ACTIVE) {
- port_int_reg = (u16) (adapter_interrupts >> 16);
- process_interrupt(port_int_reg, icom_port);
- check_modem_status(icom_port);
- }
- }
- /* Clear out any pending interrupts */
- writel(adapter_interrupts, int_reg);
- /* flush the write */
- adapter_interrupts = readl(int_reg);
- return IRQ_HANDLED;
- }
- /*
- * ------------------------------------------------------------------
- * Begin serial-core API
- * ------------------------------------------------------------------
- */
- static unsigned int icom_tx_empty(struct uart_port *port)
- {
- int ret;
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
- if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &
- SA_FLAGS_READY_TO_XMIT)
- ret = TIOCSER_TEMT;
- else
- ret = 0;
- spin_unlock_irqrestore(&port->lock, flags);
- return ret;
- }
- static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl)
- {
- unsigned char local_osr;
- trace(ICOM_PORT, "SET_MODEM", 0);
- local_osr = readb(&ICOM_PORT->dram->osr);
- if (mctrl & TIOCM_RTS) {
- trace(ICOM_PORT, "RAISE_RTS", 0);
- local_osr |= ICOM_RTS;
- } else {
- trace(ICOM_PORT, "LOWER_RTS", 0);
- local_osr &= ~ICOM_RTS;
- }
- if (mctrl & TIOCM_DTR) {
- trace(ICOM_PORT, "RAISE_DTR", 0);
- local_osr |= ICOM_DTR;
- } else {
- trace(ICOM_PORT, "LOWER_DTR", 0);
- local_osr &= ~ICOM_DTR;
- }
- writeb(local_osr, &ICOM_PORT->dram->osr);
- }
- static unsigned int icom_get_mctrl(struct uart_port *port)
- {
- unsigned char status;
- unsigned int result;
- trace(ICOM_PORT, "GET_MODEM", 0);
- status = readb(&ICOM_PORT->dram->isr);
- result = ((status & ICOM_DCD) ? TIOCM_CAR : 0)
- | ((status & ICOM_RI) ? TIOCM_RNG : 0)
- | ((status & ICOM_DSR) ? TIOCM_DSR : 0)
- | ((status & ICOM_CTS) ? TIOCM_CTS : 0);
- return result;
- }
- static void icom_stop_tx(struct uart_port *port)
- {
- unsigned char cmdReg;
- trace(ICOM_PORT, "STOP", 0);
- cmdReg = readb(&ICOM_PORT->dram->CmdReg);
- writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);
- }
- static void icom_start_tx(struct uart_port *port)
- {
- unsigned char cmdReg;
- trace(ICOM_PORT, "START", 0);
- cmdReg = readb(&ICOM_PORT->dram->CmdReg);
- if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT)
- writeb(cmdReg & ~CMD_HOLD_XMIT,
- &ICOM_PORT->dram->CmdReg);
- icom_write(port);
- }
- static void icom_send_xchar(struct uart_port *port, char ch)
- {
- unsigned char xdata;
- int index;
- unsigned long flags;
- trace(ICOM_PORT, "SEND_XCHAR", ch);
- /* wait .1 sec to send char */
- for (index = 0; index < 10; index++) {
- spin_lock_irqsave(&port->lock, flags);
- xdata = readb(&ICOM_PORT->dram->xchar);
- if (xdata == 0x00) {
- trace(ICOM_PORT, "QUICK_WRITE", 0);
- writeb(ch, &ICOM_PORT->dram->xchar);
- /* flush write operation */
- xdata = readb(&ICOM_PORT->dram->xchar);
- spin_unlock_irqrestore(&port->lock, flags);
- break;
- }
- spin_unlock_irqrestore(&port->lock, flags);
- msleep(10);
- }
- }
- static void icom_stop_rx(struct uart_port *port)
- {
- unsigned char cmdReg;
- cmdReg = readb(&ICOM_PORT->dram->CmdReg);
- writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
- }
- static void icom_break(struct uart_port *port, int break_state)
- {
- unsigned char cmdReg;
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
- trace(ICOM_PORT, "BREAK", 0);
- cmdReg = readb(&ICOM_PORT->dram->CmdReg);
- if (break_state == -1) {
- writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
- } else {
- writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);
- }
- spin_unlock_irqrestore(&port->lock, flags);
- }
- static int icom_open(struct uart_port *port)
- {
- int retval;
- kref_get(&ICOM_PORT->adapter->kref);
- retval = startup(ICOM_PORT);
- if (retval) {
- kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
- trace(ICOM_PORT, "STARTUP_ERROR", 0);
- return retval;
- }
- return 0;
- }
- static void icom_close(struct uart_port *port)
- {
- unsigned char cmdReg;
- trace(ICOM_PORT, "CLOSE", 0);
- /* stop receiver */
- cmdReg = readb(&ICOM_PORT->dram->CmdReg);
- writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
- shutdown(ICOM_PORT);
- kref_put(&ICOM_PORT->adapter->kref, icom_kref_release);
- }
- static void icom_set_termios(struct uart_port *port,
- struct ktermios *termios,
- struct ktermios *old_termios)
- {
- int baud;
- unsigned cflag, iflag;
- char new_config2;
- char new_config3 = 0;
- char tmp_byte;
- int index;
- int rcv_buff, xmit_buff;
- unsigned long offset;
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
- trace(ICOM_PORT, "CHANGE_SPEED", 0);
- cflag = termios->c_cflag;
- iflag = termios->c_iflag;
- new_config2 = ICOM_ACFG_DRIVE1;
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5: /* 5 bits/char */
- new_config2 |= ICOM_ACFG_5BPC;
- break;
- case CS6: /* 6 bits/char */
- new_config2 |= ICOM_ACFG_6BPC;
- break;
- case CS7: /* 7 bits/char */
- new_config2 |= ICOM_ACFG_7BPC;
- break;
- case CS8: /* 8 bits/char */
- new_config2 |= ICOM_ACFG_8BPC;
- break;
- default:
- break;
- }
- if (cflag & CSTOPB) {
- /* 2 stop bits */
- new_config2 |= ICOM_ACFG_2STOP_BIT;
- }
- if (cflag & PARENB) {
- /* parity bit enabled */
- new_config2 |= ICOM_ACFG_PARITY_ENAB;
- trace(ICOM_PORT, "PARENB", 0);
- }
- if (cflag & PARODD) {
- /* odd parity */
- new_config2 |= ICOM_ACFG_PARITY_ODD;
- trace(ICOM_PORT, "PARODD", 0);
- }
- /* Determine divisor based on baud rate */
- baud = uart_get_baud_rate(port, termios, old_termios,
- icom_acfg_baud[0],
- icom_acfg_baud[BAUD_TABLE_LIMIT]);
- if (!baud)
- baud = 9600; /* B0 transition handled in rs_set_termios */
- for (index = 0; index < BAUD_TABLE_LIMIT; index++) {
- if (icom_acfg_baud[index] == baud) {
- new_config3 = index;
- break;
- }
- }
- uart_update_timeout(port, cflag, baud);
- /* CTS flow control flag and modem status interrupts */
- tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
- if (cflag & CRTSCTS)
- tmp_byte |= HDLC_HDW_FLOW;
- else
- tmp_byte &= ~HDLC_HDW_FLOW;
- writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
- /*
- * Set up parity check flag
- */
- ICOM_PORT->read_status_mask = SA_FLAGS_OVERRUN | SA_FL_RCV_DONE;
- if (iflag & INPCK)
- ICOM_PORT->read_status_mask |=
- SA_FLAGS_FRAME_ERROR | SA_FLAGS_PARITY_ERROR;
- if ((iflag & BRKINT) || (iflag & PARMRK))
- ICOM_PORT->read_status_mask |= SA_FLAGS_BREAK_DET;
- /*
- * Characters to ignore
- */
- ICOM_PORT->ignore_status_mask = 0;
- if (iflag & IGNPAR)
- ICOM_PORT->ignore_status_mask |=
- SA_FLAGS_PARITY_ERROR | SA_FLAGS_FRAME_ERROR;
- if (iflag & IGNBRK) {
- ICOM_PORT->ignore_status_mask |= SA_FLAGS_BREAK_DET;
- /*
- * If we're ignore parity and break indicators, ignore
- * overruns too. (For real raw support).
- */
- if (iflag & IGNPAR)
- ICOM_PORT->ignore_status_mask |= SA_FLAGS_OVERRUN;
- }
- /*
- * !!! ignore all characters if CREAD is not set
- */
- if ((cflag & CREAD) == 0)
- ICOM_PORT->ignore_status_mask |= SA_FL_RCV_DONE;
- /* Turn off Receiver to prepare for reset */
- writeb(CMD_RCV_DISABLE, &ICOM_PORT->dram->CmdReg);
- for (index = 0; index < 10; index++) {
- if (readb(&ICOM_PORT->dram->PrevCmdReg) == 0x00) {
- break;
- }
- }
- /* clear all current buffers of data */
- for (rcv_buff = 0; rcv_buff < NUM_RBUFFS; rcv_buff++) {
- ICOM_PORT->statStg->rcv[rcv_buff].flags = 0;
- ICOM_PORT->statStg->rcv[rcv_buff].leLength = 0;
- ICOM_PORT->statStg->rcv[rcv_buff].WorkingLength =
- (unsigned short int) cpu_to_le16(RCV_BUFF_SZ);
- }
- for (xmit_buff = 0; xmit_buff < NUM_XBUFFS; xmit_buff++) {
- ICOM_PORT->statStg->xmit[xmit_buff].flags = 0;
- }
- /* activate changes and start xmit and receiver here */
- /* Enable the receiver */
- writeb(new_config3, &(ICOM_PORT->dram->async_config3));
- writeb(new_config2, &(ICOM_PORT->dram->async_config2));
- tmp_byte = readb(&(ICOM_PORT->dram->HDLCConfigReg));
- tmp_byte |= HDLC_PPP_PURE_ASYNC | HDLC_FF_FILL;
- writeb(tmp_byte, &(ICOM_PORT->dram->HDLCConfigReg));
- writeb(0x04, &(ICOM_PORT->dram->FlagFillIdleTimer)); /* 0.5 seconds */
- writeb(0xFF, &(ICOM_PORT->dram->ier)); /* enable modem signal interrupts */
- /* reset processor */
- writeb(CMD_RESTART, &ICOM_PORT->dram->CmdReg);
- for (index = 0; index < 10; index++) {
- if (readb(&ICOM_PORT->dram->CmdReg) == 0x00) {
- break;
- }
- }
- /* Enable Transmitter and Receiver */
- offset =
- (unsigned long) &ICOM_PORT->statStg->rcv[0] -
- (unsigned long) ICOM_PORT->statStg;
- writel(ICOM_PORT->statStg_pci + offset,
- &ICOM_PORT->dram->RcvStatusAddr);
- ICOM_PORT->next_rcv = 0;
- ICOM_PORT->put_length = 0;
- *ICOM_PORT->xmitRestart = 0;
- writel(ICOM_PORT->xmitRestart_pci,
- &ICOM_PORT->dram->XmitStatusAddr);
- trace(ICOM_PORT, "XR_ENAB", 0);
- writeb(CMD_XMIT_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);
- spin_unlock_irqrestore(&port->lock, flags);
- }
- static const char *icom_type(struct uart_port *port)
- {
- return "icom";
- }
- static void icom_release_port(struct uart_port *port)
- {
- }
- static int icom_request_port(struct uart_port *port)
- {
- return 0;
- }
- static void icom_config_port(struct uart_port *port, int flags)
- {
- port->type = PORT_ICOM;
- }
- static struct uart_ops icom_ops = {
- .tx_empty = icom_tx_empty,
- .set_mctrl = icom_set_mctrl,
- .get_mctrl = icom_get_mctrl,
- .stop_tx = icom_stop_tx,
- .start_tx = icom_start_tx,
- .send_xchar = icom_send_xchar,
- .stop_rx = icom_stop_rx,
- .break_ctl = icom_break,
- .startup = icom_open,
- .shutdown = icom_close,
- .set_termios = icom_set_termios,
- .type = icom_type,
- .release_port = icom_release_port,
- .request_port = icom_request_port,
- .config_port = icom_config_port,
- };
- #define ICOM_CONSOLE NULL
- static struct uart_driver icom_uart_driver = {
- .owner = THIS_MODULE,
- .driver_name = ICOM_DRIVER_NAME,
- .dev_name = "ttyA",
- .major = ICOM_MAJOR,
- .minor = ICOM_MINOR_START,
- .nr = NR_PORTS,
- .cons = ICOM_CONSOLE,
- };
- static int icom_init_ports(struct icom_adapter *icom_adapter)
- {
- u32 subsystem_id = icom_adapter->subsystem_id;
- int i;
- struct icom_port *icom_port;
- if (icom_adapter->version == ADAPTER_V1) {
- icom_adapter->numb_ports = 2;
- for (i = 0; i < 2; i++) {
- icom_port = &icom_adapter->port_info[i];
- icom_port->port = i;
- icom_port->status = ICOM_PORT_ACTIVE;
- icom_port->imbed_modem = ICOM_UNKNOWN;
- }
- } else {
- if (subsystem_id == PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL) {
- icom_adapter->numb_ports = 4;
- for (i = 0; i < 4; i++) {
- icom_port = &icom_adapter->port_info[i];
- icom_port->port = i;
- icom_port->status = ICOM_PORT_ACTIVE;
- icom_port->imbed_modem = ICOM_IMBED_MODEM;
- }
- } else {
- icom_adapter->numb_ports = 4;
- icom_adapter->port_info[0].port = 0;
- icom_adapter->port_info[0].status = ICOM_PORT_ACTIVE;
- if (subsystem_id ==
- PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM) {
- icom_adapter->port_info[0].imbed_modem = ICOM_IMBED_MODEM;
- } else {
- icom_adapter->port_info[0].imbed_modem = ICOM_RVX;
- }
- icom_adapter->port_info[1].status = ICOM_PORT_OFF;
- icom_adapter->port_info[2].port = 2;
- icom_adapter->port_info[2].status = ICOM_PORT_ACTIVE;
- icom_adapter->port_info[2].imbed_modem = ICOM_RVX;
- icom_adapter->port_info[3].status = ICOM_PORT_OFF;
- }
- }
- return 0;
- }
- static void icom_port_active(struct icom_port *icom_port, struct icom_adapter *icom_adapter, int port_num)
- {
- if (icom_adapter->version == ADAPTER_V1) {
- icom_port->global_reg = icom_adapter->base_addr + 0x4000;
- icom_port->int_reg = icom_adapter->base_addr +
- 0x4004 + 2 - 2 * port_num;
- } else {
- icom_port->global_reg = icom_adapter->base_addr + 0x8000;
- if (icom_port->port < 2)
- icom_port->int_reg = icom_adapter->base_addr +
- 0x8004 + 2 - 2 * icom_port->port;
- else
- icom_port->int_reg = icom_adapter->base_addr +
- 0x8024 + 2 - 2 * (icom_port->port - 2);
- }
- }
- static int icom_load_ports(struct icom_adapter *icom_adapter)
- {
- struct icom_port *icom_port;
- int port_num;
- for (port_num = 0; port_num < icom_adapter->numb_ports; port_num++) {
- icom_port = &icom_adapter->port_info[port_num];
- if (icom_port->status == ICOM_PORT_ACTIVE) {
- icom_port_active(icom_port, icom_adapter, port_num);
- icom_port->dram = icom_adapter->base_addr +
- 0x2000 * icom_port->port;
- icom_port->adapter = icom_adapter;
- /* get port memory */
- if (get_port_memory(icom_port) != 0) {
- dev_err(&icom_port->adapter->pci_dev->dev,
- "Memory allocation for port FAILED\n");
- }
- }
- }
- return 0;
- }
- static int icom_alloc_adapter(struct icom_adapter
- **icom_adapter_ref)
- {
- int adapter_count = 0;
- struct icom_adapter *icom_adapter;
- struct icom_adapter *cur_adapter_entry;
- struct list_head *tmp;
- icom_adapter = kzalloc(sizeof(struct icom_adapter), GFP_KERNEL);
- if (!icom_adapter) {
- return -ENOMEM;
- }
- list_for_each(tmp, &icom_adapter_head) {
- cur_adapter_entry =
- list_entry(tmp, struct icom_adapter,
- icom_adapter_entry);
- if (cur_adapter_entry->index != adapter_count) {
- break;
- }
- adapter_count++;
- }
- icom_adapter->index = adapter_count;
- list_add_tail(&icom_adapter->icom_adapter_entry, tmp);
- *icom_adapter_ref = icom_adapter;
- return 0;
- }
- static void icom_free_adapter(struct icom_adapter *icom_adapter)
- {
- list_del(&icom_adapter->icom_adapter_entry);
- kfree(icom_adapter);
- }
- static void icom_remove_adapter(struct icom_adapter *icom_adapter)
- {
- struct icom_port *icom_port;
- int index;
- for (index = 0; index < icom_adapter->numb_ports; index++) {
- icom_port = &icom_adapter->port_info[index];
- if (icom_port->status == ICOM_PORT_ACTIVE) {
- dev_info(&icom_adapter->pci_dev->dev,
- "Device removed\n");
- uart_remove_one_port(&icom_uart_driver,
- &icom_port->uart_port);
- /* be sure that DTR and RTS are dropped */
- writeb(0x00, &icom_port->dram->osr);
- /* Wait 0.1 Sec for simple Init to complete */
- msleep(100);
- /* Stop proccessor */
- stop_processor(icom_port);
- free_port_memory(icom_port);
- }
- }
- free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter);
- iounmap(icom_adapter->base_addr);
- pci_release_regions(icom_adapter->pci_dev);
- icom_free_adapter(icom_adapter);
- }
- static void icom_kref_release(struct kref *kref)
- {
- struct icom_adapter *icom_adapter;
- icom_adapter = to_icom_adapter(kref);
- icom_remove_adapter(icom_adapter);
- }
- static int icom_probe(struct pci_dev *dev,
- const struct pci_device_id *ent)
- {
- int index;
- unsigned int command_reg;
- int retval;
- struct icom_adapter *icom_adapter;
- struct icom_port *icom_port;
- retval = pci_enable_device(dev);
- if (retval) {
- dev_err(&dev->dev, "Device enable FAILED\n");
- return retval;
- }
- retval = pci_request_regions(dev, "icom");
- if (retval) {
- dev_err(&dev->dev, "pci_request_regions FAILED\n");
- pci_disable_device(dev);
- return retval;
- }
- pci_set_master(dev);
- retval = pci_read_config_dword(dev, PCI_COMMAND, &command_reg);
- if (retval) {
- dev_err(&dev->dev, "PCI Config read FAILED\n");
- return retval;
- }
- pci_write_config_dword(dev, PCI_COMMAND,
- command_reg | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER
- | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
- if (ent->driver_data == ADAPTER_V1) {
- pci_write_config_dword(dev, 0x44, 0x8300830A);
- } else {
- pci_write_config_dword(dev, 0x44, 0x42004200);
- pci_write_config_dword(dev, 0x48, 0x42004200);
- }
- retval = icom_alloc_adapter(&icom_adapter);
- if (retval) {
- dev_err(&dev->dev, "icom_alloc_adapter FAILED\n");
- retval = -EIO;
- goto probe_exit0;
- }
- icom_adapter->base_addr_pci = pci_resource_start(dev, 0);
- icom_adapter->pci_dev = dev;
- icom_adapter->version = ent->driver_data;
- icom_adapter->subsystem_id = ent->subdevice;
- retval = icom_init_ports(icom_adapter);
- if (retval) {
- dev_err(&dev->dev, "Port configuration failed\n");
- goto probe_exit1;
- }
- icom_adapter->base_addr = pci_ioremap_bar(dev, 0);
- if (!icom_adapter->base_addr) {
- retval = -ENOMEM;
- goto probe_exit1;
- }
- /* save off irq and request irq line */
- retval = request_irq(dev->irq, icom_interrupt, IRQF_SHARED, ICOM_DRIVER_NAME, (void *)icom_adapter);
- if (retval) {
- goto probe_exit2;
- }
- retval = icom_load_ports(icom_adapter);
- for (index = 0; index < icom_adapter->numb_ports; index++) {
- icom_port = &icom_adapter->port_info[index];
- if (icom_port->status == ICOM_PORT_ACTIVE) {
- icom_port->uart_port.irq = icom_port->adapter->pci_dev->irq;
- icom_port->uart_port.type = PORT_ICOM;
- icom_port->uart_port.iotype = UPIO_MEM;
- icom_port->uart_port.membase =
- (unsigned char __iomem *)icom_adapter->base_addr_pci;
- icom_port->uart_port.fifosize = 16;
- icom_port->uart_port.ops = &icom_ops;
- icom_port->uart_port.line =
- icom_port->port + icom_adapter->index * 4;
- if (uart_add_one_port (&icom_uart_driver, &icom_port->uart_port)) {
- icom_port->status = ICOM_PORT_OFF;
- dev_err(&dev->dev, "Device add failed\n");
- } else
- dev_info(&dev->dev, "Device added\n");
- }
- }
- kref_init(&icom_adapter->kref);
- return 0;
- probe_exit2:
- iounmap(icom_adapter->base_addr);
- probe_exit1:
- icom_free_adapter(icom_adapter);
- probe_exit0:
- pci_release_regions(dev);
- pci_disable_device(dev);
- return retval;
- }
- static void icom_remove(struct pci_dev *dev)
- {
- struct icom_adapter *icom_adapter;
- struct list_head *tmp;
- list_for_each(tmp, &icom_adapter_head) {
- icom_adapter = list_entry(tmp, struct icom_adapter,
- icom_adapter_entry);
- if (icom_adapter->pci_dev == dev) {
- kref_put(&icom_adapter->kref, icom_kref_release);
- return;
- }
- }
- dev_err(&dev->dev, "Unable to find device to remove\n");
- }
- static struct pci_driver icom_pci_driver = {
- .name = ICOM_DRIVER_NAME,
- .id_table = icom_pci_table,
- .probe = icom_probe,
- .remove = icom_remove,
- };
- static int __init icom_init(void)
- {
- int ret;
- spin_lock_init(&icom_lock);
- ret = uart_register_driver(&icom_uart_driver);
- if (ret)
- return ret;
- ret = pci_register_driver(&icom_pci_driver);
- if (ret < 0)
- uart_unregister_driver(&icom_uart_driver);
- return ret;
- }
- static void __exit icom_exit(void)
- {
- pci_unregister_driver(&icom_pci_driver);
- uart_unregister_driver(&icom_uart_driver);
- }
- module_init(icom_init);
- module_exit(icom_exit);
- MODULE_AUTHOR("Michael Anderson <mjanders@us.ibm.com>");
- MODULE_DESCRIPTION("IBM iSeries Serial IOA driver");
- MODULE_SUPPORTED_DEVICE
- ("IBM iSeries 2745, 2771, 2772, 2742, 2793 and 2805 Communications adapters");
- MODULE_LICENSE("GPL");
- /*(DEBLOBBED)*/
|