X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fserial%2Fioc4_serial.c;h=a37579ce6d763c89223787ba01b782633038397d;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=c620209d7b9a5d70e31e933dd998026d0196a677;hpb=f7ed79d23a47594e7834d66a8f14449796d4f3e6;p=linux-2.6.git diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index c620209d7..a37579ce6 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -3,7 +3,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * Copyright (C) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (C) 2003-2005 Silicon Graphics, Inc. All Rights Reserved. */ @@ -323,12 +323,9 @@ static unsigned int Num_of_ioc4_cards; #define IOC4_FIFO_CHARS 255 /* Device name we're using */ -#define DEVICE_NAME_RS232 "ttyIOC" -#define DEVICE_NAME_RS422 "ttyAIOC" -#define DEVICE_MAJOR 204 -#define DEVICE_MINOR_RS232 50 -#define DEVICE_MINOR_RS422 84 - +#define DEVICE_NAME "ttyIOC" +#define DEVICE_MAJOR 204 +#define DEVICE_MINOR 50 /* register offsets */ #define IOC4_SERIAL_OFFSET 0x300 @@ -344,8 +341,10 @@ static unsigned int Num_of_ioc4_cards; #define MAX_BAUD_SUPPORTED 115200 /* protocol types supported */ -#define PROTO_RS232 3 -#define PROTO_RS422 7 +enum sio_proto { + PROTO_RS232, + PROTO_RS422 +}; /* Notification types */ #define N_DATA_READY 0x01 @@ -396,17 +395,11 @@ static unsigned int Num_of_ioc4_cards; /* * This is the entry saved by the driver - one per card */ - -#define UART_PORT_MIN 0 -#define UART_PORT_RS232 UART_PORT_MIN -#define UART_PORT_RS422 1 -#define UART_PORT_COUNT 2 /* one for each mode */ - struct ioc4_control { int ic_irq; struct { - /* uart ports are allocated here - 1 for rs232, 1 for rs422 */ - struct uart_port icp_uart_port[UART_PORT_COUNT]; + /* uart ports are allocated here */ + struct uart_port icp_uart_port; /* Handy reference material */ struct ioc4_port *icp_port; } ic_port[IOC4_NUM_SERIAL_PORTS]; @@ -450,9 +443,7 @@ struct ioc4_soft { /* Local port info for each IOC4 serial ports */ struct ioc4_port { - struct uart_port *ip_port; /* current active port ptr */ - /* Ptrs for all ports */ - struct uart_port *ip_all_ports[UART_PORT_COUNT]; + struct uart_port *ip_port; /* Back ptrs for this port */ struct ioc4_control *ip_control; struct pci_dev *ip_pdev; @@ -511,9 +502,6 @@ struct ioc4_port { #define DCD_ON 0x02 #define LOWAT_WRITTEN 0x04 #define READ_ABORTED 0x08 -#define PORT_ACTIVE 0x10 -#define PORT_INACTIVE 0 /* This is the value when "off" */ - /* Since each port has different register offsets and bitmasks * for everything, we'll store those that we need in tables so we @@ -635,23 +623,6 @@ struct ring_buffer { static void receive_chars(struct uart_port *); static void handle_intr(void *arg, uint32_t sio_ir); -/* - * port_is_active - determines if this port is currently active - * @port: ptr to soft struct for this port - * @uart_port: uart port to test for - */ -static inline int port_is_active(struct ioc4_port *port, - struct uart_port *uart_port) -{ - if (port) { - if ((port->ip_flags & PORT_ACTIVE) - && (port->ip_port == uart_port)) - return 1; - } - return 0; -} - - /** * write_ireg - write the interrupt regs * @ioc4_soft: ptr to soft struct for this port @@ -737,33 +708,19 @@ static int set_baud(struct ioc4_port *port, int baud) /** * get_ioc4_port - given a uart port, return the control structure * @port: uart port - * @set: set this port as current */ -static struct ioc4_port *get_ioc4_port(struct uart_port *the_port, int set) +static struct ioc4_port *get_ioc4_port(struct uart_port *the_port) { struct ioc4_driver_data *idd = dev_get_drvdata(the_port->dev); struct ioc4_control *control = idd->idd_serial_data; - struct ioc4_port *port; - int port_num, port_type; + int ii; if (control) { - for ( port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; - port_num++ ) { - port = control->ic_port[port_num].icp_port; - if (!port) + for ( ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++ ) { + if (!control->ic_port[ii].icp_port) continue; - for (port_type = UART_PORT_MIN; - port_type < UART_PORT_COUNT; - port_type++) { - if (the_port == port->ip_all_ports - [port_type]) { - /* set local copy */ - if (set) { - port->ip_port = the_port; - } - return port; - } - } + if (the_port == control->ic_port[ii].icp_port->ip_port) + return control->ic_port[ii].icp_port; } } return NULL; @@ -989,7 +946,6 @@ intr_connect(struct ioc4_soft *soft, int type, * @arg: handler arg * @regs: registers */ - static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) { struct ioc4_soft *soft; @@ -997,7 +953,7 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) int xx, num_intrs = 0; int intr_type; int handled = 0; - struct ioc4_intr_info *intr_info; + struct ioc4_intr_info *ii; soft = arg; for (intr_type = 0; intr_type < IOC4_NUM_INTR_TYPES; intr_type++) { @@ -1010,13 +966,13 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) * which interrupt bits are set. */ for (xx = 0; xx < num_intrs; xx++) { - intr_info = &soft->is_intr_type[intr_type].is_intr_info[xx]; - if ((this_mir = this_ir & intr_info->sd_bits)) { + ii = &soft->is_intr_type[intr_type].is_intr_info[xx]; + if ((this_mir = this_ir & ii->sd_bits)) { /* Disable owned interrupts, call handler */ handled++; - write_ireg(soft, intr_info->sd_bits, IOC4_W_IEC, + write_ireg(soft, ii->sd_bits, IOC4_W_IEC, intr_type); - intr_info->sd_intr(intr_info->sd_info, this_mir); + ii->sd_intr(ii->sd_info, this_mir); this_ir &= ~this_mir; } } @@ -1024,6 +980,7 @@ static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs) #ifdef DEBUG_INTERRUPTS { struct ioc4_misc_regs __iomem *mem = soft->is_ioc4_misc_addr; + spinlock_t *lp = &soft->is_ir_lock; unsigned long flag; spin_lock_irqsave(&soft->is_ir_lock, flag); @@ -1220,7 +1177,7 @@ static inline int local_open(struct ioc4_port *port) { int spiniter = 0; - port->ip_flags = PORT_ACTIVE; + port->ip_flags = 0; /* Pause the DMA interface if necessary */ if (port->ip_sscr & IOC4_SSCR_DMA_EN) { @@ -1230,7 +1187,6 @@ static inline int local_open(struct ioc4_port *port) & IOC4_SSCR_PAUSE_STATE) == 0) { spiniter++; if (spiniter > MAXITER) { - port->ip_flags = PORT_INACTIVE; return -1; } } @@ -1550,13 +1506,14 @@ static int set_notification(struct ioc4_port *port, int mask, int set_on) /** * set_mcr - set the master control reg * @the_port: port to use + * @set: set ? * @mask1: mcr mask * @mask2: shadow mask */ -static inline int set_mcr(struct uart_port *the_port, +static inline int set_mcr(struct uart_port *the_port, int set, int mask1, int mask2) { - struct ioc4_port *port = get_ioc4_port(the_port, 0); + struct ioc4_port *port = get_ioc4_port(the_port); uint32_t shadow; int spiniter = 0; char mcr; @@ -1579,9 +1536,13 @@ static inline int set_mcr(struct uart_port *the_port, mcr = (shadow & 0xff000000) >> 24; /* Set new value */ - mcr |= mask1; - shadow |= mask2; - + if (set) { + mcr |= mask1; + shadow |= mask2; + } else { + mcr &= ~mask1; + shadow &= ~mask2; + } writeb(mcr, &port->ip_uart_regs->i4u_mcr); writel(shadow, &port->ip_serial_regs->shadow); @@ -1597,7 +1558,7 @@ static inline int set_mcr(struct uart_port *the_port, * @port: port to use * @proto: protocol to use */ -static int ioc4_set_proto(struct ioc4_port *port, int proto) +static int ioc4_set_proto(struct ioc4_port *port, enum sio_proto proto) { struct hooks *hooks = port->ip_hooks; @@ -1628,7 +1589,7 @@ static void transmit_chars(struct uart_port *the_port) int result; char *start; struct tty_struct *tty; - struct ioc4_port *port = get_ioc4_port(the_port, 0); + struct ioc4_port *port = get_ioc4_port(the_port); struct uart_info *info; if (!the_port) @@ -1684,7 +1645,7 @@ static void ioc4_change_speed(struct uart_port *the_port, struct termios *new_termios, struct termios *old_termios) { - struct ioc4_port *port = get_ioc4_port(the_port, 0); + struct ioc4_port *port = get_ioc4_port(the_port); int baud, bits; unsigned cflag; int new_parity = 0, new_parity_enable = 0, new_stop = 0, new_data = 8; @@ -1791,7 +1752,7 @@ static inline int ic4_startup_local(struct uart_port *the_port) if (!the_port) return -1; - port = get_ioc4_port(the_port, 0); + port = get_ioc4_port(the_port); if (!port) return -1; @@ -1799,9 +1760,6 @@ static inline int ic4_startup_local(struct uart_port *the_port) local_open(port); - /* set the protocol - mapbase has the port type */ - ioc4_set_proto(port, the_port->mapbase); - /* set the speed of the serial port */ ioc4_change_speed(the_port, info->tty->termios, (struct termios *)0); @@ -1810,17 +1768,17 @@ static inline int ic4_startup_local(struct uart_port *the_port) /* * ioc4_cb_output_lowat - called when the output low water mark is hit - * @the_port: port to output + * @port: port to output */ -static void ioc4_cb_output_lowat(struct uart_port *the_port) +static void ioc4_cb_output_lowat(struct ioc4_port *port) { unsigned long pflags; /* ip_lock is set on the call here */ - if (the_port) { - spin_lock_irqsave(&the_port->lock, pflags); - transmit_chars(the_port); - spin_unlock_irqrestore(&the_port->lock, pflags); + if (port->ip_port) { + spin_lock_irqsave(&port->ip_port->lock, pflags); + transmit_chars(port->ip_port); + spin_unlock_irqrestore(&port->ip_port->lock, pflags); } } @@ -1965,7 +1923,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) &port->ip_mem->sio_ir.raw); if (port->ip_notify & N_OUTPUT_LOWAT) - ioc4_cb_output_lowat(port->ip_port); + ioc4_cb_output_lowat(port); } /* Handle tx_mt. Must come after tx_explicit. */ @@ -1978,7 +1936,7 @@ static void handle_intr(void *arg, uint32_t sio_ir) * So send the notification now. */ if (port->ip_notify & N_OUTPUT_LOWAT) { - ioc4_cb_output_lowat(port->ip_port); + ioc4_cb_output_lowat(port); /* We need to reload the sio_ir since the lowat * call may have caused another write to occur, @@ -2065,7 +2023,7 @@ static inline int do_read(struct uart_port *the_port, unsigned char *buf, int len) { int prod_ptr, cons_ptr, total; - struct ioc4_port *port = get_ioc4_port(the_port, 0); + struct ioc4_port *port = get_ioc4_port(the_port); struct ring *inring; struct ring_entry *entry; struct hooks *hooks = port->ip_hooks; @@ -2377,27 +2335,17 @@ static void receive_chars(struct uart_port *the_port) */ static const char *ic4_type(struct uart_port *the_port) { - if (the_port->mapbase == PROTO_RS232) - return "SGI IOC4 Serial [rs232]"; - else - return "SGI IOC4 Serial [rs422]"; + return "SGI IOC4 Serial"; } /** - * ic4_tx_empty - Is the transmitter empty? - * @port: Port to operate on + * ic4_tx_empty - Is the transmitter empty? We pretend we're always empty + * @port: Port to operate on (we ignore since we always return 1) * */ static unsigned int ic4_tx_empty(struct uart_port *the_port) { - struct ioc4_port *port = get_ioc4_port(the_port, 0); - unsigned int ret = 0; - - if (port_is_active(port, the_port)) { - if (readl(&port->ip_serial_regs->shadow) & IOC4_SHADOW_TEMT) - ret = TIOCSER_TEMT; - } - return ret; + return 1; } /** @@ -2407,10 +2355,6 @@ static unsigned int ic4_tx_empty(struct uart_port *the_port) */ static void ic4_stop_tx(struct uart_port *the_port) { - struct ioc4_port *port = get_ioc4_port(the_port, 0); - - if (port_is_active(port, the_port)) - set_notification(port, N_OUTPUT_LOWAT, 0); } /** @@ -2433,12 +2377,11 @@ static void ic4_shutdown(struct uart_port *the_port) struct ioc4_port *port; struct uart_info *info; - port = get_ioc4_port(the_port, 0); + port = get_ioc4_port(the_port); if (!port) return; info = the_port->info; - port->ip_port = NULL; wake_up_interruptible(&info->delta_msr_wait); @@ -2447,7 +2390,6 @@ static void ic4_shutdown(struct uart_port *the_port) spin_lock_irqsave(&the_port->lock, port_flags); set_notification(port, N_ALL, 0); - port->ip_flags = PORT_INACTIVE; spin_unlock_irqrestore(&the_port->lock, port_flags); } @@ -2460,11 +2402,6 @@ static void ic4_shutdown(struct uart_port *the_port) static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl) { unsigned char mcr = 0; - struct ioc4_port *port; - - port = get_ioc4_port(the_port, 0); - if (!port_is_active(port, the_port)) - return; if (mctrl & TIOCM_RTS) mcr |= UART_MCR_RTS; @@ -2477,7 +2414,7 @@ static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl) if (mctrl & TIOCM_LOOP) mcr |= UART_MCR_LOOP; - set_mcr(the_port, mcr, IOC4_SHADOW_DTR); + set_mcr(the_port, 1, mcr, IOC4_SHADOW_DTR); } /** @@ -2487,11 +2424,11 @@ static void ic4_set_mctrl(struct uart_port *the_port, unsigned int mctrl) */ static unsigned int ic4_get_mctrl(struct uart_port *the_port) { - struct ioc4_port *port = get_ioc4_port(the_port, 0); + struct ioc4_port *port = get_ioc4_port(the_port); uint32_t shadow; unsigned int ret = 0; - if (!port_is_active(port, the_port)) + if (!port) return 0; shadow = readl(&port->ip_serial_regs->shadow); @@ -2511,9 +2448,9 @@ static unsigned int ic4_get_mctrl(struct uart_port *the_port) */ static void ic4_start_tx(struct uart_port *the_port) { - struct ioc4_port *port = get_ioc4_port(the_port, 0); + struct ioc4_port *port = get_ioc4_port(the_port); - if (port_is_active(port, the_port)) { + if (port) { set_notification(port, N_OUTPUT_LOWAT, 1); enable_intrs(port, port->ip_hooks->intr_tx_mt); } @@ -2530,7 +2467,7 @@ static void ic4_break_ctl(struct uart_port *the_port, int break_state) } /** - * ic4_startup - Start up the serial port + * ic4_startup - Start up the serial port - always return 0 (We're always on) * @port: Port to operate on * */ @@ -2542,16 +2479,17 @@ static int ic4_startup(struct uart_port *the_port) struct uart_info *info; unsigned long port_flags; - if (!the_port) + if (!the_port) { return -ENODEV; - port = get_ioc4_port(the_port, 1); - if (!port) + } + port = get_ioc4_port(the_port); + if (!port) { return -ENODEV; + } info = the_port->info; control = port->ip_control; if (!control) { - port->ip_port = NULL; return -ENODEV; } @@ -2613,104 +2551,28 @@ static struct uart_ops ioc4_ops = { * Boot-time initialization code */ -static struct uart_driver ioc4_uart_rs232 = { +static struct uart_driver ioc4_uart = { .owner = THIS_MODULE, - .driver_name = "ioc4_serial_rs232", - .dev_name = DEVICE_NAME_RS232, + .driver_name = "ioc4_serial", + .dev_name = DEVICE_NAME, .major = DEVICE_MAJOR, - .minor = DEVICE_MINOR_RS232, + .minor = DEVICE_MINOR, .nr = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS, }; -static struct uart_driver ioc4_uart_rs422 = { - .owner = THIS_MODULE, - .driver_name = "ioc4_serial_rs422", - .dev_name = DEVICE_NAME_RS422, - .major = DEVICE_MAJOR, - .minor = DEVICE_MINOR_RS422, - .nr = IOC4_NUM_CARDS * IOC4_NUM_SERIAL_PORTS, -}; - - /** - * ioc4_serial_remove_one - detach function - * - * @idd: IOC4 master module data for this IOC4 - */ - -static int ioc4_serial_remove_one(struct ioc4_driver_data *idd) -{ - int port_num, port_type; - struct ioc4_control *control; - struct uart_port *the_port; - struct ioc4_port *port; - struct ioc4_soft *soft; - - control = idd->idd_serial_data; - - for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) { - for (port_type = UART_PORT_MIN; - port_type < UART_PORT_COUNT; - port_type++) { - the_port = &control->ic_port[port_num].icp_uart_port - [port_type]; - if (the_port) { - switch (port_type) { - case UART_PORT_RS422: - uart_remove_one_port(&ioc4_uart_rs422, - the_port); - break; - default: - case UART_PORT_RS232: - uart_remove_one_port(&ioc4_uart_rs232, - the_port); - break; - } - } - } - port = control->ic_port[port_num].icp_port; - /* we allocate in pairs */ - if (!(port_num & 1) && port) { - pci_free_consistent(port->ip_pdev, - TOTAL_RING_BUF_SIZE, - port->ip_cpu_ringbuf, - port->ip_dma_ringbuf); - kfree(port); - } - } - soft = control->ic_soft; - if (soft) { - free_irq(control->ic_irq, soft); - if (soft->is_ioc4_serial_addr) { - release_region((unsigned long) - soft->is_ioc4_serial_addr, - sizeof(struct ioc4_serial)); - } - kfree(soft); - } - kfree(control); - idd->idd_serial_data = NULL; - - return 0; -} - - -/** - * ioc4_serial_core_attach_rs232 - register with serial core + * ioc4_serial_core_attach - register with serial core * This is done during pci probing * @pdev: handle for this card */ static inline int -ioc4_serial_core_attach(struct pci_dev *pdev, int port_type) +ioc4_serial_core_attach(struct pci_dev *pdev) { struct ioc4_port *port; struct uart_port *the_port; struct ioc4_driver_data *idd = pci_get_drvdata(pdev); struct ioc4_control *control = idd->idd_serial_data; - int port_num; - int port_type_idx; - struct uart_driver *u_driver; - + int ii; DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n", __FUNCTION__, pdev, (void *)control)); @@ -2718,36 +2580,28 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type) if (!control) return -ENODEV; - port_type_idx = (port_type == PROTO_RS232) ? UART_PORT_RS232 - : UART_PORT_RS422; - - u_driver = (port_type == PROTO_RS232) ? &ioc4_uart_rs232 - : &ioc4_uart_rs422; - /* once around for each port on this card */ - for (port_num = 0; port_num < IOC4_NUM_SERIAL_PORTS; port_num++) { - the_port = &control->ic_port[port_num].icp_uart_port - [port_type_idx]; - port = control->ic_port[port_num].icp_port; - port->ip_all_ports[port_type_idx] = the_port; + for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) { + the_port = &control->ic_port[ii].icp_uart_port; + port = control->ic_port[ii].icp_port; + port->ip_port = the_port; - DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n", + DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p\n", __FUNCTION__, (void *)the_port, - (void *)port, - port_type == PROTO_RS232 ? "rs232" : "rs422")); + (void *)port)); /* membase, iobase and mapbase just need to be non-0 */ the_port->membase = (unsigned char __iomem *)1; - the_port->iobase = (pdev->bus->number << 16) | port_num; - the_port->line = (Num_of_ioc4_cards << 2) | port_num; - the_port->mapbase = port_type; + the_port->iobase = (pdev->bus->number << 16) | ii; + the_port->line = (Num_of_ioc4_cards << 2) | ii; + the_port->mapbase = 1; the_port->type = PORT_16550A; the_port->fifosize = IOC4_FIFO_CHARS; the_port->ops = &ioc4_ops; the_port->irq = control->ic_irq; the_port->dev = &pdev->dev; spin_lock_init(&the_port->lock); - if (uart_add_one_port(u_driver, the_port) < 0) { + if (uart_add_one_port(&ioc4_uart, the_port) < 0) { printk(KERN_WARNING "%s: unable to add port %d bus %d\n", __FUNCTION__, the_port->line, pdev->bus->number); @@ -2756,6 +2610,8 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type) ("IOC4 serial port %d irq = %d, bus %d\n", the_port->line, the_port->irq, pdev->bus->number)); } + /* all ports are rs232 for now */ + ioc4_set_proto(port, PROTO_RS232); } return 0; } @@ -2775,8 +2631,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) int ret = 0; - DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev, - idd->idd_pci_id)); + DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev, idd->idd_pci_id)); /* request serial registers */ tmp_addr1 = idd->idd_bar0 + IOC4_SERIAL_OFFSET; @@ -2798,11 +2653,11 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) goto out2; } DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n", - __FUNCTION__, (void *)idd->idd_misc_regs, - (void *)serial)); + __FUNCTION__, (void *)idd->idd_misc_regs, (void *)serial)); /* Get memory for the new card */ - control = kmalloc(sizeof(struct ioc4_control), GFP_KERNEL); + control = kmalloc(sizeof(struct ioc4_control) * IOC4_NUM_SERIAL_PORTS, + GFP_KERNEL); if (!control) { printk(KERN_WARNING "ioc4_attach_one" @@ -2847,7 +2702,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) /* Hook up interrupt handler */ if (!request_irq(idd->idd_pdev->irq, ioc4_intr, SA_SHIRQ, - "sgi-ioc4serial", soft)) { + "sgi-ioc4serial", (void *)soft)) { control->ic_irq = idd->idd_pdev->irq; } else { printk(KERN_WARNING @@ -2858,21 +2713,16 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) if (ret) goto out4; - /* register port with the serial core - 1 rs232, 1 rs422 */ + /* register port with the serial core */ - if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS232))) + if ((ret = ioc4_serial_core_attach(idd->idd_pdev))) goto out4; - if ((ret = ioc4_serial_core_attach(idd->idd_pdev, PROTO_RS422))) - goto out5; - Num_of_ioc4_cards++; return ret; /* error exits that give back resources */ -out5: - ioc4_serial_remove_one(idd); out4: kfree(soft); out3: @@ -2885,6 +2735,52 @@ out1: } +/** + * ioc4_serial_remove_one - detach function + * + * @idd: IOC4 master module data for this IOC4 + */ + +int ioc4_serial_remove_one(struct ioc4_driver_data *idd) +{ + int ii; + struct ioc4_control *control; + struct uart_port *the_port; + struct ioc4_port *port; + struct ioc4_soft *soft; + + control = idd->idd_serial_data; + + for (ii = 0; ii < IOC4_NUM_SERIAL_PORTS; ii++) { + the_port = &control->ic_port[ii].icp_uart_port; + if (the_port) { + uart_remove_one_port(&ioc4_uart, the_port); + } + port = control->ic_port[ii].icp_port; + if (!(ii & 1) && port) { + pci_free_consistent(port->ip_pdev, + TOTAL_RING_BUF_SIZE, + (void *)port->ip_cpu_ringbuf, + port->ip_dma_ringbuf); + kfree(port); + } + } + soft = control->ic_soft; + if (soft) { + free_irq(control->ic_irq, (void *)soft); + if (soft->is_ioc4_serial_addr) { + release_region((unsigned long) + soft->is_ioc4_serial_addr, + sizeof(struct ioc4_serial)); + } + kfree(soft); + } + kfree(control); + idd->idd_serial_data = NULL; + + return 0; +} + static struct ioc4_submodule ioc4_serial_submodule = { .is_name = "IOC4_serial", .is_owner = THIS_MODULE, @@ -2900,15 +2796,9 @@ int ioc4_serial_init(void) int ret; /* register with serial core */ - if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) { - printk(KERN_WARNING - "%s: Couldn't register rs232 IOC4 serial driver\n", - __FUNCTION__); - return ret; - } - if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) { + if ((ret = uart_register_driver(&ioc4_uart)) < 0) { printk(KERN_WARNING - "%s: Couldn't register rs422 IOC4 serial driver\n", + "%s: Couldn't register IOC4 serial driver\n", __FUNCTION__); return ret; } @@ -2920,8 +2810,7 @@ int ioc4_serial_init(void) static void __devexit ioc4_serial_exit(void) { ioc4_unregister_submodule(&ioc4_serial_submodule); - uart_unregister_driver(&ioc4_uart_rs232); - uart_unregister_driver(&ioc4_uart_rs422); + uart_unregister_driver(&ioc4_uart); } module_init(ioc4_serial_init);