X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fchar%2Fpcmcia%2Fsynclink_cs.c;h=f108c136800a2ef3b2fcb990cc3d8aabf83b6ffe;hb=refs%2Fheads%2Fvserver;hp=fb87f872fab6976e2b56a4e13133225ae7dd8770;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index fb87f872f..f108c1368 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -1,7 +1,7 @@ /* * linux/drivers/char/pcmcia/synclink_cs.c * - * $Id: synclink_cs.c,v 4.21 2004/03/08 15:29:23 paulkf Exp $ + * $Id: synclink_cs.c,v 4.34 2005/09/08 13:20:54 paulkf Exp $ * * Device driver for Microgate SyncLink PC Card * multiprotocol serial adapter. @@ -35,12 +35,12 @@ #define MAX_DEVICE_COUNT 4 -#include #include #include #include #include #include +#include #include #include #include @@ -56,7 +56,6 @@ #include #include #include -#include #include #include @@ -64,24 +63,22 @@ #include #include #include -#include +#include #include #include #include +#include -#include #include #include #include #include #include -#ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE -#define CONFIG_SYNCLINK_SYNCPPP 1 -#endif - -#ifdef CONFIG_SYNCLINK_SYNCPPP -#include +#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_CS_MODULE)) +#define SYNCLINK_GENERIC_HDLC 1 +#else +#define SYNCLINK_GENERIC_HDLC 0 #endif #define GET_USER(error,value,addr) error = get_user(value,addr) @@ -231,7 +228,7 @@ typedef struct _mgslpc_info { struct _input_signal_events input_signal_events; /* PCMCIA support */ - dev_link_t link; + struct pcmcia_device *p_dev; dev_node_t node; int stop; @@ -239,12 +236,11 @@ typedef struct _mgslpc_info { int netcount; int dosyncppp; spinlock_t netlock; -#ifdef CONFIG_SYNCLINK_SYNCPPP - struct ppp_device pppdev; - char netname[10]; + +#if SYNCLINK_GENERIC_HDLC struct net_device *netdev; - struct net_device_stats netstats; #endif + } MGSLPC_INFO; #define MGSLPC_MAGIC 0x5402 @@ -257,7 +253,12 @@ typedef struct _mgslpc_info { #define CHA 0x00 /* channel A offset */ #define CHB 0x40 /* channel B offset */ - + +/* + * FIXME: PPC has PVR defined in asm/reg.h. For now we just undef it. + */ +#undef PVR + #define RXFIFO 0 #define TXFIFO 0 #define STAR 0x20 @@ -393,18 +394,12 @@ static void tx_timeout(unsigned long context); static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg); -#ifdef CONFIG_SYNCLINK_SYNCPPP -/* SPPP/HDLC stuff */ -static void mgslpc_sppp_init(MGSLPC_INFO *info); -static void mgslpc_sppp_delete(MGSLPC_INFO *info); -static int mgslpc_sppp_open(struct net_device *d); -static int mgslpc_sppp_close(struct net_device *d); -static void mgslpc_sppp_tx_timeout(struct net_device *d); -static int mgslpc_sppp_tx(struct sk_buff *skb, struct net_device *d); -static void mgslpc_sppp_rx_done(MGSLPC_INFO *info, char *buf, int size); -static void mgslpc_sppp_tx_done(MGSLPC_INFO *info); -static int mgslpc_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); -struct net_device_stats *mgslpc_net_stats(struct net_device *dev); +#if SYNCLINK_GENERIC_HDLC +#define dev_to_port(D) (dev_to_hdlc(D)->priv) +static void hdlcdev_tx_done(MGSLPC_INFO *info); +static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size); +static int hdlcdev_init(MGSLPC_INFO *info); +static void hdlcdev_exit(MGSLPC_INFO *info); #endif static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit); @@ -423,12 +418,12 @@ static void rx_reset_buffers(MGSLPC_INFO *info); static int rx_alloc_buffers(MGSLPC_INFO *info); static void rx_free_buffers(MGSLPC_INFO *info); -static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs); +static irqreturn_t mgslpc_isr(int irq, void *dev_id); /* * Bottom half interrupt handlers */ -static void bh_handler(void* Context); +static void bh_handler(struct work_struct *work); static void bh_transmit(MGSLPC_INFO *info); static void bh_status(MGSLPC_INFO *info); @@ -438,17 +433,15 @@ static void bh_status(MGSLPC_INFO *info); static int tiocmget(struct tty_struct *tty, struct file *file); static int tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); -static int get_stats(MGSLPC_INFO *info, struct mgsl_icount *user_icount); -static int get_params(MGSLPC_INFO *info, MGSL_PARAMS *user_params); -static int set_params(MGSLPC_INFO *info, MGSL_PARAMS *new_params); -static int get_txidle(MGSLPC_INFO *info, int*idle_mode); +static int get_stats(MGSLPC_INFO *info, struct mgsl_icount __user *user_icount); +static int get_params(MGSLPC_INFO *info, MGSL_PARAMS __user *user_params); +static int set_params(MGSLPC_INFO *info, MGSL_PARAMS __user *new_params); +static int get_txidle(MGSLPC_INFO *info, int __user *idle_mode); static int set_txidle(MGSLPC_INFO *info, int idle_mode); static int set_txenable(MGSLPC_INFO *info, int enable); static int tx_abort(MGSLPC_INFO *info); static int set_rxenable(MGSLPC_INFO *info, int enable); -static int wait_events(MGSLPC_INFO *info, int *mask); - -#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) +static int wait_events(MGSLPC_INFO *info, int __user *mask); static MGSLPC_INFO *mgslpc_device_list = NULL; static int mgslpc_device_count = 0; @@ -470,26 +463,16 @@ static int debug_level = 0; static int maxframe[MAX_DEVICE_COUNT] = {0,}; static int dosyncppp[MAX_DEVICE_COUNT] = {1,1,1,1}; -/* The old way: bit map of interrupts to choose from */ -/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ -static u_int irq_mask = 0xdeb8; - -/* Newer, simpler way of listing specific interrupts */ -static int irq_list[4] = { -1 }; - -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); - -MODULE_PARM(break_on_load,"i"); -MODULE_PARM(ttymajor,"i"); -MODULE_PARM(debug_level,"i"); -MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i"); -MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i"); +module_param(break_on_load, bool, 0); +module_param(ttymajor, int, 0); +module_param(debug_level, int, 0); +module_param_array(maxframe, int, NULL, 0); +module_param_array(dosyncppp, int, NULL, 0); MODULE_LICENSE("GPL"); static char *driver_name = "SyncLink PC Card driver"; -static char *driver_version = "$Revision: 4.21 $"; +static char *driver_version = "$Revision: 4.34 $"; static struct tty_driver *serial_driver; @@ -499,21 +482,11 @@ static struct tty_driver *serial_driver; static void mgslpc_change_params(MGSLPC_INFO *info); static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout); -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - /* PCMCIA prototypes */ -static void mgslpc_config(dev_link_t *link); +static int mgslpc_config(struct pcmcia_device *link); static void mgslpc_release(u_long arg); -static int mgslpc_event(event_t event, int priority, - event_callback_args_t *args); -static dev_link_t *mgslpc_attach(void); -static void mgslpc_detach(dev_link_t *); - -static dev_info_t dev_info = "synclink_cs"; -static dev_link_t *dev_list = NULL; +static void mgslpc_detach(struct pcmcia_device *p_dev); /* * 1st function defined in .text section. Calling this function in @@ -521,28 +494,62 @@ static dev_link_t *dev_list = NULL; * (gdb) to get the .text address for the add-symbol-file command. * This allows remote debugging of dynamically loadable modules. */ -static void* mgslpc_get_text_ptr(void); -static void* mgslpc_get_text_ptr() {return mgslpc_get_text_ptr;} +static void* mgslpc_get_text_ptr(void) +{ + return mgslpc_get_text_ptr; +} + +/** + * line discipline callback wrappers + * + * The wrappers maintain line discipline references + * while calling into the line discipline. + * + * ldisc_flush_buffer - flush line discipline receive buffers + * ldisc_receive_buf - pass receive data to line discipline + */ + +static void ldisc_flush_buffer(struct tty_struct *tty) +{ + struct tty_ldisc *ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->flush_buffer) + ld->flush_buffer(tty); + tty_ldisc_deref(ld); + } +} -static dev_link_t *mgslpc_attach(void) +static void ldisc_receive_buf(struct tty_struct *tty, + const __u8 *data, char *flags, int count) +{ + struct tty_ldisc *ld; + if (!tty) + return; + ld = tty_ldisc_ref(tty); + if (ld) { + if (ld->receive_buf) + ld->receive_buf(tty, data, flags, count); + tty_ldisc_deref(ld); + } +} + +static int mgslpc_probe(struct pcmcia_device *link) { MGSLPC_INFO *info; - dev_link_t *link; - client_reg_t client_reg; - int ret, i; - + int ret; + if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_attach\n"); - - info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); + + info = kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); if (!info) { printk("Error can't allocate device instance data\n"); - return NULL; + return -ENOMEM; } memset(info, 0, sizeof(MGSLPC_INFO)); info->magic = MGSLPC_MAGIC; - INIT_WORK(&info->task, bh_handler, info); + INIT_WORK(&info->task, bh_handler); info->max_frame_size = 4096; info->close_delay = 5*HZ/10; info->closing_wait = 30*HZ; @@ -558,49 +565,26 @@ static dev_link_t *mgslpc_attach(void) info->imrb_value = 0xffff; info->pim_value = 0xff; - link = &info->link; + info->p_dev = link; link->priv = info; - - /* Initialize the dev_link_t structure */ + + /* Initialize the struct pcmcia_device structure */ /* Interrupt setup */ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; - if (irq_list[0] == -1) - link->irq.IRQInfo2 = irq_mask; - else - for (i = 0; i < 4; i++) - link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = NULL; - + link->conf.Attributes = 0; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; - /* Register with Card Services */ - link->next = dev_list; - dev_list = link; - - client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &mgslpc_event; - client_reg.Version = 0x0210; - client_reg.event_callback_args.client_data = link; - - ret = pcmcia_register_client(&link->handle, &client_reg); - if (ret != CS_SUCCESS) { - cs_error(link->handle, RegisterClient, ret); - mgslpc_detach(link); - return NULL; - } + ret = mgslpc_config(link); + if (ret) + return ret; mgslpc_add_device(info); - return link; + return 0; } /* Card has been inserted. @@ -609,48 +593,32 @@ static dev_link_t *mgslpc_attach(void) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static void mgslpc_config(dev_link_t *link) +static int mgslpc_config(struct pcmcia_device *link) { - client_handle_t handle = link->handle; MGSLPC_INFO *info = link->priv; tuple_t tuple; cisparse_t parse; int last_fn, last_ret; u_char buf[64]; - config_info_t conf; cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg; if (debug_level >= DEBUG_LEVEL_INFO) printk("mgslpc_config(0x%p)\n", link); - /* read CONFIG tuple to find its configuration registers */ - tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* Configure card */ - link->state |= DEV_CONFIG; - - /* Look up the current Vcc */ - CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf)); - link->conf.Vcc = conf.Vcc; /* get CIS configuration entry */ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); cfg = &(parse.cftable_entry); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; if (cfg->index == 0) @@ -671,11 +639,10 @@ static void mgslpc_config(dev_link_t *link) link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; link->io.BasePort1 = io->win[0].base; link->io.NumPorts1 = io->win[0].len; - CS_CHECK(RequestIO, pcmcia_request_io(link->handle, &link->io)); + CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); } link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 8; link->conf.Present = PRESENT_OPTION; @@ -683,9 +650,9 @@ static void mgslpc_config(dev_link_t *link) link->irq.Attributes |= IRQ_HANDLE_PRESENT; link->irq.Handler = mgslpc_isr; link->irq.Instance = info; - CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq)); + CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link->handle, &link->conf)); + CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); info->io_base = link->io.BasePort1; info->irq_level = link->irq.AssignedIRQ; @@ -693,7 +660,7 @@ static void mgslpc_config(dev_link_t *link) /* add to linked list of devices */ sprintf(info->node.dev_name, "mgslpc0"); info->node.major = info->node.minor = 0; - link->dev = &info->node; + link->dev_node = &info->node; printk(KERN_INFO "%s: index 0x%02x:", info->node.dev_name, link->conf.ConfigIndex); @@ -703,13 +670,12 @@ static void mgslpc_config(dev_link_t *link) printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1); printk("\n"); - - link->state &= ~DEV_CONFIG_PENDING; - return; + return 0; cs_failed: - cs_error(link->handle, last_fn, last_ret); + cs_error(link, last_fn, last_ret); mgslpc_release((u_long)link); + return -ENODEV; } /* Card has been removed. @@ -718,99 +684,44 @@ cs_failed: */ static void mgslpc_release(u_long arg) { - dev_link_t *link = (dev_link_t *)arg; + struct pcmcia_device *link = (struct pcmcia_device *)arg; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_release(0x%p)\n", link); + if (debug_level >= DEBUG_LEVEL_INFO) + printk("mgslpc_release(0x%p)\n", link); - /* Unlink the device chain */ - link->dev = NULL; - link->state &= ~DEV_CONFIG; + pcmcia_disable_device(link); +} - pcmcia_release_configuration(link->handle); - if (link->io.NumPorts1) - pcmcia_release_io(link->handle, &link->io); - if (link->irq.AssignedIRQ) - pcmcia_release_irq(link->handle, &link->irq); - if (link->state & DEV_STALE_LINK) - mgslpc_detach(link); +static void mgslpc_detach(struct pcmcia_device *link) +{ + if (debug_level >= DEBUG_LEVEL_INFO) + printk("mgslpc_detach(0x%p)\n", link); + + ((MGSLPC_INFO *)link->priv)->stop = 1; + mgslpc_release((u_long)link); + + mgslpc_remove_device((MGSLPC_INFO *)link->priv); } -static void mgslpc_detach(dev_link_t *link) +static int mgslpc_suspend(struct pcmcia_device *link) { - dev_link_t **linkp; + MGSLPC_INFO *info = link->priv; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_detach(0x%p)\n", link); - - /* find device */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) break; - if (*linkp == NULL) - return; - - if (link->state & DEV_CONFIG) { - /* device is configured/active, mark it so when - * release() is called a proper detach() occurs. - */ - if (debug_level >= DEBUG_LEVEL_INFO) - printk(KERN_DEBUG "synclinkpc: detach postponed, '%s' " - "still locked\n", link->dev->dev_name); - link->state |= DEV_STALE_LINK; - return; - } + info->stop = 1; - /* Break the link with Card Services */ - if (link->handle) - pcmcia_deregister_client(link->handle); - - /* Unlink device structure, and free it */ - *linkp = link->next; - mgslpc_remove_device((MGSLPC_INFO *)link->priv); + return 0; } -static int mgslpc_event(event_t event, int priority, - event_callback_args_t *args) +static int mgslpc_resume(struct pcmcia_device *link) { - dev_link_t *link = args->client_data; - MGSLPC_INFO *info = link->priv; - - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_event(0x%06x)\n", event); - - switch (event) { - case CS_EVENT_CARD_REMOVAL: - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) { - ((MGSLPC_INFO *)link->priv)->stop = 1; - mgslpc_release((u_long)link); - } - break; - case CS_EVENT_CARD_INSERTION: - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - mgslpc_config(link); - break; - case CS_EVENT_PM_SUSPEND: - link->state |= DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_RESET_PHYSICAL: - /* Mark the device as stopped, to block IO until later */ - info->stop = 1; - if (link->state & DEV_CONFIG) - pcmcia_release_configuration(link->handle); - break; - case CS_EVENT_PM_RESUME: - link->state &= ~DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_CARD_RESET: - if (link->state & DEV_CONFIG) - pcmcia_request_configuration(link->handle, &link->conf); - info->stop = 0; - break; - } - return 0; + MGSLPC_INFO *info = link->priv; + + info->stop = 0; + + return 0; } + static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, char *name, const char *routine) { @@ -847,9 +758,8 @@ static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, static BOOLEAN wait_command_complete(MGSLPC_INFO *info, unsigned char channel) { int i = 0; - unsigned char status; /* wait for command completion */ - while ((status = read_reg(info, (unsigned char)(channel+STAR)) & BIT2)) { + while (read_reg(info, (unsigned char)(channel+STAR)) & BIT2) { udelay(1); if (i++ == 1000) return FALSE; @@ -898,7 +808,7 @@ static void tx_release(struct tty_struct *tty) /* Return next bottom half action to perform. * or 0 if nothing to do. */ -int bh_action(MGSLPC_INFO *info) +static int bh_action(MGSLPC_INFO *info) { unsigned long flags; int rc = 0; @@ -927,9 +837,9 @@ int bh_action(MGSLPC_INFO *info) return rc; } -void bh_handler(void* Context) +static void bh_handler(struct work_struct *work) { - MGSLPC_INFO *info = (MGSLPC_INFO*)Context; + MGSLPC_INFO *info = container_of(work, MGSLPC_INFO, task); int action; if (!info) @@ -971,25 +881,19 @@ void bh_handler(void* Context) __FILE__,__LINE__,info->device_name); } -void bh_transmit(MGSLPC_INFO *info) +static void bh_transmit(MGSLPC_INFO *info) { struct tty_struct *tty = info->tty; if (debug_level >= DEBUG_LEVEL_BH) printk("bh_transmit() entry on %s\n", info->device_name); if (tty) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) { - if ( debug_level >= DEBUG_LEVEL_BH ) - printk( "%s(%d):calling ldisc.write_wakeup on %s\n", - __FILE__,__LINE__,info->device_name); - (tty->ldisc.write_wakeup)(tty); - } + tty_wakeup(tty); wake_up_interruptible(&tty->write_wait); } } -void bh_status(MGSLPC_INFO *info) +static void bh_status(MGSLPC_INFO *info) { info->ri_chkcount = 0; info->dsr_chkcount = 0; @@ -998,7 +902,7 @@ void bh_status(MGSLPC_INFO *info) } /* eom: non-zero = end of frame */ -void rx_ready_hdlc(MGSLPC_INFO *info, int eom) +static void rx_ready_hdlc(MGSLPC_INFO *info, int eom) { unsigned char data[2]; unsigned char fifo_count, read_count, i; @@ -1060,10 +964,11 @@ void rx_ready_hdlc(MGSLPC_INFO *info, int eom) issue_command(info, CHA, CMD_RXFIFO); } -void rx_ready_async(MGSLPC_INFO *info, int tcd) +static void rx_ready_async(MGSLPC_INFO *info, int tcd) { - unsigned char data, status; + unsigned char data, status, flag; int fifo_count; + int work = 0; struct tty_struct *tty = info->tty; struct mgsl_icount *icount = &info->icount; @@ -1078,20 +983,16 @@ void rx_ready_async(MGSLPC_INFO *info, int tcd) fifo_count = 32; } else fifo_count = 32; - + + tty_buffer_request_room(tty, fifo_count); /* Flush received async data to receive data buffer. */ while (fifo_count) { data = read_reg(info, CHA + RXFIFO); status = read_reg(info, CHA + RXFIFO); fifo_count -= 2; - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - break; - - *tty->flip.char_buf_ptr = data; icount->rx++; - - *tty->flip.flag_buf_ptr = 0; + flag = TTY_NORMAL; // if no frameing/crc error then save data // BIT7:parity error @@ -1110,31 +1011,28 @@ void rx_ready_async(MGSLPC_INFO *info, int tcd) status &= info->read_status_mask; if (status & BIT7) - *tty->flip.flag_buf_ptr = TTY_PARITY; + flag = TTY_PARITY; else if (status & BIT6) - *tty->flip.flag_buf_ptr = TTY_FRAME; + flag = TTY_FRAME; } - - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; + work += tty_insert_flip_char(tty, data, flag); } issue_command(info, CHA, CMD_RXFIFO); if (debug_level >= DEBUG_LEVEL_ISR) { - printk("%s(%d):rx_ready_async count=%d\n", - __FILE__,__LINE__,tty->flip.count); + printk("%s(%d):rx_ready_async", + __FILE__,__LINE__); printk("%s(%d):rx=%d brk=%d parity=%d frame=%d overrun=%d\n", __FILE__,__LINE__,icount->rx,icount->brk, icount->parity,icount->frame,icount->overrun); } - if (tty->flip.count) + if (work) tty_flip_buffer_push(tty); } -void tx_done(MGSLPC_INFO *info) +static void tx_done(MGSLPC_INFO *info) { if (!info->tx_active) return; @@ -1157,9 +1055,9 @@ void tx_done(MGSLPC_INFO *info) info->drop_rts_on_tx_done = 0; } -#ifdef CONFIG_SYNCLINK_SYNCPPP +#if SYNCLINK_GENERIC_HDLC if (info->netcount) - mgslpc_sppp_tx_done(info); + hdlcdev_tx_done(info); else #endif { @@ -1171,7 +1069,7 @@ void tx_done(MGSLPC_INFO *info) } } -void tx_ready(MGSLPC_INFO *info) +static void tx_ready(MGSLPC_INFO *info) { unsigned char fifo_count = 32; int c; @@ -1195,7 +1093,7 @@ void tx_ready(MGSLPC_INFO *info) return; while (info->tx_count && fifo_count) { - c = MIN(2, MIN(fifo_count, MIN(info->tx_count, TXBUFSIZE - info->tx_get))); + c = min(2, min_t(int, fifo_count, min(info->tx_count, TXBUFSIZE - info->tx_get))); if (c == 1) { write_reg(info, CHA + TXFIFO, *(info->tx_buf + info->tx_get)); @@ -1220,7 +1118,7 @@ void tx_ready(MGSLPC_INFO *info) } } -void cts_change(MGSLPC_INFO *info) +static void cts_change(MGSLPC_INFO *info) { get_signals(info); if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) @@ -1257,7 +1155,7 @@ void cts_change(MGSLPC_INFO *info) info->pending_bh |= BH_STATUS; } -void dcd_change(MGSLPC_INFO *info) +static void dcd_change(MGSLPC_INFO *info) { get_signals(info); if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) @@ -1265,13 +1163,17 @@ void dcd_change(MGSLPC_INFO *info) info->icount.dcd++; if (info->serial_signals & SerialSignal_DCD) { info->input_signal_events.dcd_up++; -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->netcount) - sppp_reopen(info->netdev); -#endif } else info->input_signal_events.dcd_down++; +#if SYNCLINK_GENERIC_HDLC + if (info->netcount) { + if (info->serial_signals & SerialSignal_DCD) + netif_carrier_on(info->netdev); + else + netif_carrier_off(info->netdev); + } +#endif wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); @@ -1291,7 +1193,7 @@ void dcd_change(MGSLPC_INFO *info) info->pending_bh |= BH_STATUS; } -void dsr_change(MGSLPC_INFO *info) +static void dsr_change(MGSLPC_INFO *info) { get_signals(info); if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) @@ -1306,7 +1208,7 @@ void dsr_change(MGSLPC_INFO *info) info->pending_bh |= BH_STATUS; } -void ri_change(MGSLPC_INFO *info) +static void ri_change(MGSLPC_INFO *info) { get_signals(info); if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT) @@ -1327,9 +1229,8 @@ void ri_change(MGSLPC_INFO *info) * * irq interrupt number that caused interrupt * dev_id device ID supplied during interrupt registration - * regs interrupted processor context */ -static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t mgslpc_isr(int irq, void *dev_id) { MGSLPC_INFO * info = (MGSLPC_INFO *)dev_id; unsigned short isr; @@ -1341,7 +1242,7 @@ static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs) if (!info) return IRQ_NONE; - if (!(info->link.state & DEV_CONFIG)) + if (!(info->p_dev->_locked)) return IRQ_HANDLED; spin_lock(&info->lock); @@ -1460,6 +1361,8 @@ static int startup(MGSLPC_INFO * info) info->pending_bh = 0; + memset(&info->icount, 0, sizeof(info->icount)); + init_timer(&info->tx_timer); info->tx_timer.data = (unsigned long)info; info->tx_timer.function = tx_timeout; @@ -1511,7 +1414,7 @@ static void shutdown(MGSLPC_INFO * info) if (info->tx_buf) { free_page((unsigned long) info->tx_buf); - info->tx_buf = 0; + info->tx_buf = NULL; } spin_lock_irqsave(&info->lock,flags); @@ -1675,7 +1578,7 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch) if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char")) return; - if (!tty || !info->tx_buf) + if (!info->tx_buf) return; spin_lock_irqsave(&info->lock,flags); @@ -1725,16 +1628,15 @@ static void mgslpc_flush_chars(struct tty_struct *tty) * Arguments: * * tty pointer to tty information structure - * from_user flag: 1 = from user process * buf pointer to buffer containing send data * count size of send data in bytes * * Returns: number of characters written */ -static int mgslpc_write(struct tty_struct * tty, int from_user, +static int mgslpc_write(struct tty_struct * tty, const unsigned char *buf, int count) { - int c, ret = 0, err; + int c, ret = 0; MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; unsigned long flags; @@ -1743,7 +1645,7 @@ static int mgslpc_write(struct tty_struct * tty, int from_user, __FILE__,__LINE__,info->device_name,count); if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") || - !tty || !info->tx_buf) + !info->tx_buf) goto cleanup; if (info->params.mode == MGSL_MODE_HDLC) { @@ -1758,21 +1660,13 @@ static int mgslpc_write(struct tty_struct * tty, int from_user, } for (;;) { - c = MIN(count, - MIN(TXBUFSIZE - info->tx_count - 1, + c = min(count, + min(TXBUFSIZE - info->tx_count - 1, TXBUFSIZE - info->tx_put)); if (c <= 0) break; - if (from_user) { - COPY_FROM_USER(err, info->tx_buf + info->tx_put, buf, c); - if (err) { - if (!ret) - ret = -EFAULT; - break; - } - } else - memcpy(info->tx_buf + info->tx_put, buf, c); + memcpy(info->tx_buf + info->tx_put, buf, c); spin_lock_irqsave(&info->lock,flags); info->tx_put = (info->tx_put + c) & (TXBUFSIZE-1); @@ -1869,11 +1763,9 @@ static void mgslpc_flush_buffer(struct tty_struct *tty) info->tx_count = info->tx_put = info->tx_get = 0; del_timer(&info->tx_timer); spin_unlock_irqrestore(&info->lock,flags); - + wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + tty_wakeup(tty); } /* Send a high-priority XON/XOFF character @@ -1955,20 +1847,24 @@ static void mgslpc_unthrottle(struct tty_struct * tty) /* get the current serial statistics */ -static int get_stats(MGSLPC_INFO * info, struct mgsl_icount *user_icount) +static int get_stats(MGSLPC_INFO * info, struct mgsl_icount __user *user_icount) { int err; if (debug_level >= DEBUG_LEVEL_INFO) printk("get_params(%s)\n", info->device_name); - COPY_TO_USER(err,user_icount, &info->icount, sizeof(struct mgsl_icount)); - if (err) - return -EFAULT; + if (!user_icount) { + memset(&info->icount, 0, sizeof(info->icount)); + } else { + COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); + if (err) + return -EFAULT; + } return 0; } /* get the current serial parameters */ -static int get_params(MGSLPC_INFO * info, MGSL_PARAMS *user_params) +static int get_params(MGSLPC_INFO * info, MGSL_PARAMS __user *user_params) { int err; if (debug_level >= DEBUG_LEVEL_INFO) @@ -1988,7 +1884,7 @@ static int get_params(MGSLPC_INFO * info, MGSL_PARAMS *user_params) * * Returns: 0 if success, otherwise error code */ -static int set_params(MGSLPC_INFO * info, MGSL_PARAMS *new_params) +static int set_params(MGSLPC_INFO * info, MGSL_PARAMS __user *new_params) { unsigned long flags; MGSL_PARAMS tmp_params; @@ -2014,7 +1910,7 @@ static int set_params(MGSLPC_INFO * info, MGSL_PARAMS *new_params) return 0; } -static int get_txidle(MGSLPC_INFO * info, int*idle_mode) +static int get_txidle(MGSLPC_INFO * info, int __user *idle_mode) { int err; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2037,7 +1933,7 @@ static int set_txidle(MGSLPC_INFO * info, int idle_mode) return 0; } -static int get_interface(MGSLPC_INFO * info, int*if_mode) +static int get_interface(MGSLPC_INFO * info, int __user *if_mode) { int err; if (debug_level >= DEBUG_LEVEL_INFO) @@ -2136,7 +2032,7 @@ static int set_rxenable(MGSLPC_INFO * info, int enable) * of events triggerred, * otherwise error code */ -static int wait_events(MGSLPC_INFO * info, int * mask_ptr) +static int wait_events(MGSLPC_INFO * info, int __user *mask_ptr) { unsigned long flags; int s; @@ -2405,24 +2301,25 @@ static int mgslpc_ioctl(struct tty_struct *tty, struct file * file, return ioctl_common(info, cmd, arg); } -int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg) +static int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg) { int error; struct mgsl_icount cnow; /* kernel counter temps */ - struct serial_icounter_struct *p_cuser; /* user space */ + struct serial_icounter_struct __user *p_cuser; /* user space */ + void __user *argp = (void __user *)arg; unsigned long flags; switch (cmd) { case MGSL_IOCGPARAMS: - return get_params(info,(MGSL_PARAMS *)arg); + return get_params(info, argp); case MGSL_IOCSPARAMS: - return set_params(info,(MGSL_PARAMS *)arg); + return set_params(info, argp); case MGSL_IOCGTXIDLE: - return get_txidle(info,(int*)arg); + return get_txidle(info, argp); case MGSL_IOCSTXIDLE: - return set_txidle(info,(int)arg); + return set_txidle(info, (int)arg); case MGSL_IOCGIF: - return get_interface(info,(int*)arg); + return get_interface(info, argp); case MGSL_IOCSIF: return set_interface(info,(int)arg); case MGSL_IOCTXENABLE: @@ -2432,16 +2329,16 @@ int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg) case MGSL_IOCTXABORT: return tx_abort(info); case MGSL_IOCGSTATS: - return get_stats(info,(struct mgsl_icount*)arg); + return get_stats(info, argp); case MGSL_IOCWAITEVENT: - return wait_events(info,(int*)arg); + return wait_events(info, argp); case TIOCMIWAIT: return modem_input_wait(info,(int)arg); case TIOCGICOUNT: spin_lock_irqsave(&info->lock,flags); cnow = info->icount; spin_unlock_irqrestore(&info->lock,flags); - p_cuser = (struct serial_icounter_struct *) arg; + p_cuser = argp; PUT_USER(error,cnow.cts, &p_cuser->cts); if (error) return error; PUT_USER(error,cnow.dsr, &p_cuser->dsr); @@ -2478,7 +2375,7 @@ int ioctl_common(MGSLPC_INFO *info, unsigned int cmd, unsigned long arg) * tty pointer to tty structure * termios pointer to buffer to hold returned old termios */ -static void mgslpc_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; unsigned long flags; @@ -2581,19 +2478,17 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp) if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); - - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + + ldisc_flush_buffer(tty); shutdown(info); tty->closing = 0; - info->tty = 0; + info->tty = NULL; if (info->blocked_open) { if (info->close_delay) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(info->close_delay); + msleep_interruptible(jiffies_to_msecs(info->close_delay)); } wake_up_interruptible(&info->open_wait); } @@ -2644,12 +2539,11 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout) char_time = 1; if (timeout) - char_time = MIN(char_time, timeout); + char_time = min_t(unsigned long, char_time, timeout); if (info->params.mode == MGSL_MODE_HDLC) { while (info->tx_active) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(char_time); + msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) @@ -2658,8 +2552,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout) } else { while ((info->tx_count || info->tx_active) && info->tx_enabled) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(char_time); + msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) @@ -2692,7 +2585,7 @@ static void mgslpc_hangup(struct tty_struct *tty) info->count = 0; info->flags &= ~ASYNC_NORMAL_ACTIVE; - info->tty = 0; + info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -2869,7 +2762,7 @@ static int mgslpc_open(struct tty_struct *tty, struct file * filp) cleanup: if (retval) { if (tty->count == 1) - info->tty = 0; /* tty layer will release tty struct */ + info->tty = NULL; /* tty layer will release tty struct */ if(info->count) info->count--; } @@ -2924,7 +2817,7 @@ static inline int line_info(char *buf, MGSLPC_INFO *info) if (info->icount.rxover) ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover); if (info->icount.rxcrc) - ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc); + ret += sprintf(buf+ret, " rxcrc:%d", info->icount.rxcrc); } else { ret += sprintf(buf+ret, " ASYNC tx:%d rx:%d", info->icount.tx, info->icount.rx); @@ -2950,7 +2843,7 @@ static inline int line_info(char *buf, MGSLPC_INFO *info) /* Called to print information about devices */ -int mgslpc_read_proc(char *page, char **start, off_t off, int count, +static int mgslpc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { int len = 0, l; @@ -2980,7 +2873,7 @@ done: return ((count < begin+len-off) ? count : begin+len-off); } -int rx_alloc_buffers(MGSLPC_INFO *info) +static int rx_alloc_buffers(MGSLPC_INFO *info) { /* each buffer has header and data */ info->rx_buf_size = sizeof(RXBUF) + info->max_frame_size; @@ -3003,14 +2896,13 @@ int rx_alloc_buffers(MGSLPC_INFO *info) return 0; } -void rx_free_buffers(MGSLPC_INFO *info) +static void rx_free_buffers(MGSLPC_INFO *info) { - if (info->rx_buf) - kfree(info->rx_buf); + kfree(info->rx_buf); info->rx_buf = NULL; } -int claim_resources(MGSLPC_INFO *info) +static int claim_resources(MGSLPC_INFO *info) { if (rx_alloc_buffers(info) < 0 ) { printk( "Cant allocate rx buffer %s\n", info->device_name); @@ -3020,7 +2912,7 @@ int claim_resources(MGSLPC_INFO *info) return 0; } -void release_resources(MGSLPC_INFO *info) +static void release_resources(MGSLPC_INFO *info) { if (debug_level >= DEBUG_LEVEL_INFO) printk("release_resources(%s)\n", info->device_name); @@ -3032,7 +2924,7 @@ void release_resources(MGSLPC_INFO *info) * * Arguments: info pointer to device instance data */ -void mgslpc_add_device(MGSLPC_INFO *info) +static void mgslpc_add_device(MGSLPC_INFO *info) { info->next_device = NULL; info->line = mgslpc_device_count; @@ -3063,16 +2955,12 @@ void mgslpc_add_device(MGSLPC_INFO *info) printk( "SyncLink PC Card %s:IO=%04X IRQ=%d\n", info->device_name, info->io_base, info->irq_level); - -#ifdef CONFIG_SYNCLINK_SYNCPPP -#ifdef MODULE - if (info->dosyncppp) -#endif - mgslpc_sppp_init(info); +#if SYNCLINK_GENERIC_HDLC + hdlcdev_init(info); #endif } -void mgslpc_remove_device(MGSLPC_INFO *remove_info) +static void mgslpc_remove_device(MGSLPC_INFO *remove_info) { MGSLPC_INFO *info = mgslpc_device_list; MGSLPC_INFO *last = NULL; @@ -3083,9 +2971,8 @@ void mgslpc_remove_device(MGSLPC_INFO *remove_info) last->next_device = info->next_device; else mgslpc_device_list = info->next_device; -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->dosyncppp) - mgslpc_sppp_delete(info); +#if SYNCLINK_GENERIC_HDLC + hdlcdev_exit(info); #endif release_resources(info); kfree(info); @@ -3097,16 +2984,25 @@ void mgslpc_remove_device(MGSLPC_INFO *remove_info) } } +static struct pcmcia_device_id mgslpc_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050), + PCMCIA_DEVICE_NULL +}; +MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids); + static struct pcmcia_driver mgslpc_driver = { .owner = THIS_MODULE, .drv = { .name = "synclink_cs", }, - .attach = mgslpc_attach, - .detach = mgslpc_detach, + .probe = mgslpc_probe, + .remove = mgslpc_detach, + .id_table = mgslpc_ids, + .suspend = mgslpc_suspend, + .resume = mgslpc_resume, }; -static struct tty_operations mgslpc_ops = { +static const struct tty_operations mgslpc_ops = { .open = mgslpc_open, .close = mgslpc_close, .write = mgslpc_write, @@ -3130,9 +3026,28 @@ static struct tty_operations mgslpc_ops = { .tiocmset = tiocmset, }; +static void synclink_cs_cleanup(void) +{ + int rc; + + printk("Unloading %s: version %s\n", driver_name, driver_version); + + while(mgslpc_device_list) + mgslpc_remove_device(mgslpc_device_list); + + if (serial_driver) { + if ((rc = tty_unregister_driver(serial_driver))) + printk("%s(%d) failed to unregister tty driver err=%d\n", + __FILE__,__LINE__,rc); + put_tty_driver(serial_driver); + } + + pcmcia_unregister_driver(&mgslpc_driver); +} + static int __init synclink_cs_init(void) { - int error; + int rc; if (break_on_load) { mgslpc_get_text_ptr(); @@ -3141,14 +3056,13 @@ static int __init synclink_cs_init(void) printk("%s %s\n", driver_name, driver_version); - serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT); - if (!serial_driver) - return -ENOMEM; + if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0) + return rc; - error = pcmcia_register_driver(&mgslpc_driver); - if (error) { - put_tty_driver(serial_driver); - return error; + serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT); + if (!serial_driver) { + rc = -ENOMEM; + goto error; } /* Initialize the tty_driver structure */ @@ -3166,45 +3080,34 @@ static int __init synclink_cs_init(void) serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &mgslpc_ops); - if (tty_register_driver(serial_driver) < 0) + if ((rc = tty_register_driver(serial_driver)) < 0) { printk("%s(%d):Couldn't register serial driver\n", __FILE__,__LINE__); + put_tty_driver(serial_driver); + serial_driver = NULL; + goto error; + } printk("%s %s, tty major#%d\n", driver_name, driver_version, serial_driver->major); return 0; + +error: + synclink_cs_cleanup(); + return rc; } static void __exit synclink_cs_exit(void) { - int rc; - - printk("Unloading %s: version %s\n", driver_name, driver_version); - - while(mgslpc_device_list) - mgslpc_remove_device(mgslpc_device_list); - - if ((rc = tty_unregister_driver(serial_driver))) - printk("%s(%d) failed to unregister tty driver err=%d\n", - __FILE__,__LINE__,rc); - put_tty_driver(serial_driver); - - pcmcia_unregister_driver(&mgslpc_driver); - - /* XXX: this really needs to move into generic code.. */ - while (dev_list != NULL) { - if (dev_list->state & DEV_CONFIG) - mgslpc_release((u_long)dev_list); - mgslpc_detach(dev_list); - } + synclink_cs_cleanup(); } module_init(synclink_cs_init); module_exit(synclink_cs_exit); -void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate) +static void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate) { unsigned int M, N; unsigned char val; @@ -3240,7 +3143,7 @@ void mgslpc_set_rate(MGSLPC_INFO *info, unsigned char channel, unsigned int rate /* Enabled the AUX clock output at the specified frequency. */ -void enable_auxclk(MGSLPC_INFO *info) +static void enable_auxclk(MGSLPC_INFO *info) { unsigned char val; @@ -3350,7 +3253,7 @@ static void loopback_enable(MGSLPC_INFO *info) write_reg(info, CHA + MODE, val); } -void hdlc_mode(MGSLPC_INFO *info) +static void hdlc_mode(MGSLPC_INFO *info) { unsigned char val; unsigned char clkmode, clksubmode; @@ -3590,7 +3493,7 @@ void hdlc_mode(MGSLPC_INFO *info) rx_stop(info); } -void rx_stop(MGSLPC_INFO *info) +static void rx_stop(MGSLPC_INFO *info) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):rx_stop(%s)\n", @@ -3603,7 +3506,7 @@ void rx_stop(MGSLPC_INFO *info) info->rx_overflow = 0; } -void rx_start(MGSLPC_INFO *info) +static void rx_start(MGSLPC_INFO *info) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):rx_start(%s)\n", @@ -3619,7 +3522,7 @@ void rx_start(MGSLPC_INFO *info) info->rx_enabled = 1; } -void tx_start(MGSLPC_INFO *info) +static void tx_start(MGSLPC_INFO *info) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):tx_start(%s)\n", @@ -3648,7 +3551,7 @@ void tx_start(MGSLPC_INFO *info) } else { info->tx_active = 1; tx_ready(info); - info->tx_timer.expires = jiffies + jiffies_from_ms(5000); + info->tx_timer.expires = jiffies + msecs_to_jiffies(5000); add_timer(&info->tx_timer); } } @@ -3657,7 +3560,7 @@ void tx_start(MGSLPC_INFO *info) info->tx_enabled = 1; } -void tx_stop(MGSLPC_INFO *info) +static void tx_stop(MGSLPC_INFO *info) { if (debug_level >= DEBUG_LEVEL_ISR) printk("%s(%d):tx_stop(%s)\n", @@ -3671,7 +3574,7 @@ void tx_stop(MGSLPC_INFO *info) /* Reset the adapter to a known state and prepare it for further use. */ -void reset_device(MGSLPC_INFO *info) +static void reset_device(MGSLPC_INFO *info) { /* power up both channels (set BIT7) */ write_reg(info, CHA + CCR0, 0x80); @@ -3721,7 +3624,7 @@ void reset_device(MGSLPC_INFO *info) write_reg(info, IPC, 0x05); } -void async_mode(MGSLPC_INFO *info) +static void async_mode(MGSLPC_INFO *info) { unsigned char val; @@ -3892,7 +3795,7 @@ void async_mode(MGSLPC_INFO *info) /* Set the HDLC idle mode for the transmitter. */ -void tx_set_idle(MGSLPC_INFO *info) +static void tx_set_idle(MGSLPC_INFO *info) { /* Note: ESCC2 only supports flags and one idle modes */ if (info->idle_mode == HDLC_TXIDLE_FLAGS) @@ -3903,7 +3806,7 @@ void tx_set_idle(MGSLPC_INFO *info) /* get state of the V24 status (input) signals. */ -void get_signals(MGSLPC_INFO *info) +static void get_signals(MGSLPC_INFO *info) { unsigned char status = 0; @@ -3925,7 +3828,7 @@ void get_signals(MGSLPC_INFO *info) /* Set the state of DTR and RTS based on contents of * serial_signals member of device extension. */ -void set_signals(MGSLPC_INFO *info) +static void set_signals(MGSLPC_INFO *info) { unsigned char val; @@ -3949,7 +3852,7 @@ void set_signals(MGSLPC_INFO *info) set_reg_bits(info, CHA + PVR, PVR_DTR); } -void rx_reset_buffers(MGSLPC_INFO *info) +static void rx_reset_buffers(MGSLPC_INFO *info) { RXBUF *buf; int i; @@ -3968,7 +3871,7 @@ void rx_reset_buffers(MGSLPC_INFO *info) * * Returns 1 if frame returned, otherwise 0 */ -int rx_get_frame(MGSLPC_INFO *info) +static int rx_get_frame(MGSLPC_INFO *info) { unsigned short status; RXBUF *buf; @@ -4000,9 +3903,12 @@ int rx_get_frame(MGSLPC_INFO *info) return_frame = 1; } framesize = 0; -#ifdef CONFIG_SYNCLINK_SYNCPPP - info->netstats.rx_errors++; - info->netstats.rx_frame_errors++; +#if SYNCLINK_GENERIC_HDLC + { + struct net_device_stats *stats = hdlc_stats(info->netdev); + stats->rx_errors++; + stats->rx_frame_errors++; + } #endif } else return_frame = 1; @@ -4031,18 +3937,12 @@ int rx_get_frame(MGSLPC_INFO *info) ++framesize; } -#ifdef CONFIG_SYNCLINK_SYNCPPP - if (info->netcount) { - /* pass frame to syncppp device */ - mgslpc_sppp_rx_done(info, buf->data, framesize); - } +#if SYNCLINK_GENERIC_HDLC + if (info->netcount) + hdlcdev_rx(info, buf->data, framesize); else #endif - { - /* Call the line discipline receive callback directly. */ - if (tty && tty->ldisc.receive_buf) - tty->ldisc.receive_buf(tty, buf->data, info->flag_buf, framesize); - } + ldisc_receive_buf(tty, buf->data, info->flag_buf, framesize); } } @@ -4057,11 +3957,11 @@ int rx_get_frame(MGSLPC_INFO *info) return 1; } -BOOLEAN register_test(MGSLPC_INFO *info) +static BOOLEAN register_test(MGSLPC_INFO *info) { static unsigned char patterns[] = { 0x00, 0xff, 0xaa, 0x55, 0x69, 0x96, 0x0f }; - static unsigned int count = sizeof(patterns) / sizeof(patterns[0]); + static unsigned int count = ARRAY_SIZE(patterns); unsigned int i; BOOLEAN rc = TRUE; unsigned long flags; @@ -4072,7 +3972,7 @@ BOOLEAN register_test(MGSLPC_INFO *info) for (i = 0; i < count; i++) { write_reg(info, XAD1, patterns[i]); write_reg(info, XAD2, patterns[(i + 1) % count]); - if ((read_reg(info, XAD1) != patterns[i]) || + if ((read_reg(info, XAD1) != patterns[i]) || (read_reg(info, XAD2) != patterns[(i + 1) % count])) { rc = FALSE; break; @@ -4083,7 +3983,7 @@ BOOLEAN register_test(MGSLPC_INFO *info) return rc; } -BOOLEAN irq_test(MGSLPC_INFO *info) +static BOOLEAN irq_test(MGSLPC_INFO *info) { unsigned long end_time; unsigned long flags; @@ -4106,8 +4006,7 @@ BOOLEAN irq_test(MGSLPC_INFO *info) end_time=100; while(end_time-- && !info->irq_occurred) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(jiffies_from_ms(10)); + msleep_interruptible(10); } info->testing_irq = FALSE; @@ -4119,7 +4018,7 @@ BOOLEAN irq_test(MGSLPC_INFO *info) return info->irq_occurred ? TRUE : FALSE; } -int adapter_test(MGSLPC_INFO *info) +static int adapter_test(MGSLPC_INFO *info) { if (!register_test(info)) { info->init_error = DiagStatus_AddressFailure; @@ -4141,7 +4040,7 @@ int adapter_test(MGSLPC_INFO *info) return 0; } -void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit) +static void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit) { int i; int linecount; @@ -4176,7 +4075,7 @@ void trace_block(MGSLPC_INFO *info,const char* data, int count, int xmit) /* HDLC frame time out * update stats and do tx completion processing */ -void tx_timeout(unsigned long context) +static void tx_timeout(unsigned long context) { MGSLPC_INFO *info = (MGSLPC_INFO*)context; unsigned long flags; @@ -4194,88 +4093,134 @@ void tx_timeout(unsigned long context) spin_unlock_irqrestore(&info->lock,flags); -#ifdef CONFIG_SYNCLINK_SYNCPPP +#if SYNCLINK_GENERIC_HDLC if (info->netcount) - mgslpc_sppp_tx_done(info); + hdlcdev_tx_done(info); else #endif bh_transmit(info); } -#ifdef CONFIG_SYNCLINK_SYNCPPP -/* syncppp net device routines +#if SYNCLINK_GENERIC_HDLC + +/** + * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.) + * set encoding and frame check sequence (FCS) options + * + * dev pointer to network device structure + * encoding serial encoding setting + * parity FCS setting + * + * returns 0 if success, otherwise error code */ - -static void mgslpc_setup(struct net_device *dev) +static int hdlcdev_attach(struct net_device *dev, unsigned short encoding, + unsigned short parity) { - dev->open = mgslpc_sppp_open; - dev->stop = mgslpc_sppp_close; - dev->hard_start_xmit = mgslpc_sppp_tx; - dev->do_ioctl = mgslpc_sppp_ioctl; - dev->get_stats = mgslpc_net_stats; - dev->tx_timeout = mgslpc_sppp_tx_timeout; - dev->watchdog_timeo = 10*HZ; -} + MGSLPC_INFO *info = dev_to_port(dev); + unsigned char new_encoding; + unsigned short new_crctype; -void mgslpc_sppp_init(MGSLPC_INFO *info) -{ - struct net_device *d; + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; - sprintf(info->netname,"mgslp%d",info->line); - - d = alloc_netdev(0, info->netname, mgslpc_setup); - if (!d) { - printk(KERN_WARNING "%s: alloc_netdev failed.\n", - info->netname); - return; + switch (encoding) + { + case ENCODING_NRZ: new_encoding = HDLC_ENCODING_NRZ; break; + case ENCODING_NRZI: new_encoding = HDLC_ENCODING_NRZI_SPACE; break; + case ENCODING_FM_MARK: new_encoding = HDLC_ENCODING_BIPHASE_MARK; break; + case ENCODING_FM_SPACE: new_encoding = HDLC_ENCODING_BIPHASE_SPACE; break; + case ENCODING_MANCHESTER: new_encoding = HDLC_ENCODING_BIPHASE_LEVEL; break; + default: return -EINVAL; } - info->if_ptr = &info->pppdev; - info->netdev = info->pppdev.dev = d; - - d->base_addr = info->io_base; - d->irq = info->irq_level; - d->priv = info; + switch (parity) + { + case PARITY_NONE: new_crctype = HDLC_CRC_NONE; break; + case PARITY_CRC16_PR1_CCITT: new_crctype = HDLC_CRC_16_CCITT; break; + case PARITY_CRC32_PR1_CCITT: new_crctype = HDLC_CRC_32_CCITT; break; + default: return -EINVAL; + } - sppp_attach(&info->pppdev); - mgslpc_setup(d); + info->params.encoding = new_encoding; + info->params.crc_type = new_crctype; - if (register_netdev(d)) { - printk(KERN_WARNING "%s: register_netdev failed.\n", d->name); - sppp_detach(info->netdev); - info->netdev = NULL; - info->pppdev.dev = NULL; - free_netdev(d); - return; - } + /* if network interface up, reprogram hardware */ + if (info->netcount) + mgslpc_program_hw(info); - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_init()\n"); + return 0; } -void mgslpc_sppp_delete(MGSLPC_INFO *info) +/** + * called by generic HDLC layer to send frame + * + * skb socket buffer containing HDLC frame + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev) { + MGSLPC_INFO *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); + unsigned long flags; + if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_delete(%s)\n",info->netname); - unregister_netdev(info->netdev); - sppp_detach(info->netdev); - free_netdev(info->netdev); - info->netdev = NULL; - info->pppdev.dev = NULL; + printk(KERN_INFO "%s:hdlc_xmit(%s)\n",__FILE__,dev->name); + + /* stop sending until this frame completes */ + netif_stop_queue(dev); + + /* copy data to device buffers */ + memcpy(info->tx_buf, skb->data, skb->len); + info->tx_get = 0; + info->tx_put = info->tx_count = skb->len; + + /* update network statistics */ + stats->tx_packets++; + stats->tx_bytes += skb->len; + + /* done with socket buffer, so free it */ + dev_kfree_skb(skb); + + /* save start time for transmit timeout detection */ + dev->trans_start = jiffies; + + /* start hardware transmitter if necessary */ + spin_lock_irqsave(&info->lock,flags); + if (!info->tx_active) + tx_start(info); + spin_unlock_irqrestore(&info->lock,flags); + + return 0; } -int mgslpc_sppp_open(struct net_device *d) +/** + * called by network layer when interface enabled + * claim resources and initialize hardware + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_open(struct net_device *dev) { - MGSLPC_INFO *info = d->priv; - int err; + MGSLPC_INFO *info = dev_to_port(dev); + int rc; unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_open(%s)\n",info->netname); + printk("%s:hdlcdev_open(%s)\n",__FILE__,dev->name); + + /* generic HDLC layer open processing */ + if ((rc = hdlc_open(dev))) + return rc; + /* arbitrate between network and tty opens */ spin_lock_irqsave(&info->netlock, flags); if (info->count != 0 || info->netcount != 0) { - printk(KERN_WARNING "%s: sppp_open returning busy\n", info->netname); + printk(KERN_WARNING "%s: hdlc_open returning busy\n", dev->name); spin_unlock_irqrestore(&info->netlock, flags); return -EBUSY; } @@ -4283,142 +4228,297 @@ int mgslpc_sppp_open(struct net_device *d) spin_unlock_irqrestore(&info->netlock, flags); /* claim resources and init adapter */ - if ((err = startup(info)) != 0) - goto open_fail; - - /* allow syncppp module to do open processing */ - if ((err = sppp_open(d)) != 0) { - shutdown(info); - goto open_fail; + if ((rc = startup(info)) != 0) { + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + return rc; } + /* assert DTR and RTS, apply hardware settings */ info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; mgslpc_program_hw(info); - d->trans_start = jiffies; - netif_start_queue(d); - return 0; + /* enable network layer transmit */ + dev->trans_start = jiffies; + netif_start_queue(dev); -open_fail: - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - return err; + /* inform generic HDLC layer of current DCD status */ + spin_lock_irqsave(&info->lock, flags); + get_signals(info); + spin_unlock_irqrestore(&info->lock, flags); + if (info->serial_signals & SerialSignal_DCD) + netif_carrier_on(dev); + else + netif_carrier_off(dev); + return 0; } -void mgslpc_sppp_tx_timeout(struct net_device *dev) +/** + * called by network layer when interface is disabled + * shutdown hardware and release resources + * + * dev pointer to network device structure + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_close(struct net_device *dev) { - MGSLPC_INFO *info = dev->priv; + MGSLPC_INFO *info = dev_to_port(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_tx_timeout(%s)\n",info->netname); + printk("%s:hdlcdev_close(%s)\n",__FILE__,dev->name); - info->netstats.tx_errors++; - info->netstats.tx_aborted_errors++; + netif_stop_queue(dev); - spin_lock_irqsave(&info->lock,flags); - tx_stop(info); - spin_unlock_irqrestore(&info->lock,flags); + /* shutdown adapter and release resources */ + shutdown(info); - netif_wake_queue(dev); + hdlc_close(dev); + + spin_lock_irqsave(&info->netlock, flags); + info->netcount=0; + spin_unlock_irqrestore(&info->netlock, flags); + + return 0; } -int mgslpc_sppp_tx(struct sk_buff *skb, struct net_device *dev) +/** + * called by network layer to process IOCTL call to network device + * + * dev pointer to network device structure + * ifr pointer to network interface request structure + * cmd IOCTL command code + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - MGSLPC_INFO *info = dev->priv; - unsigned long flags; + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; + sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; + MGSLPC_INFO *info = dev_to_port(dev); + unsigned int flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_tx(%s)\n",info->netname); + printk("%s:hdlcdev_ioctl(%s)\n",__FILE__,dev->name); - netif_stop_queue(dev); + /* return error if TTY interface open */ + if (info->count) + return -EBUSY; - info->tx_count = skb->len; + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); - memcpy(info->tx_buf, skb->data, skb->len); - info->tx_get = 0; - info->tx_put = info->tx_count = skb->len; + switch(ifr->ifr_settings.type) { + case IF_GET_IFACE: /* return current sync_serial_settings */ - info->netstats.tx_packets++; - info->netstats.tx_bytes += skb->len; - dev_kfree_skb(skb); + ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } - dev->trans_start = jiffies; + flags = info->params.flags & (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + + switch (flags){ + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN): new_line.clock_type = CLOCK_EXT; break; + case (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_INT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG): new_line.clock_type = CLOCK_TXINT; break; + case (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN): new_line.clock_type = CLOCK_TXFROMRX; break; + default: new_line.clock_type = CLOCK_DEFAULT; + } - spin_lock_irqsave(&info->lock,flags); - if (!info->tx_active) - tx_start(info); - spin_unlock_irqrestore(&info->lock,flags); + new_line.clock_rate = info->params.clock_speed; + new_line.loopback = info->params.loopback ? 1:0; - return 0; + if (copy_to_user(line, &new_line, size)) + return -EFAULT; + return 0; + + case IF_IFACE_SYNC_SERIAL: /* set sync_serial_settings */ + + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + switch (new_line.clock_type) + { + case CLOCK_EXT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_TXCPIN; break; + case CLOCK_TXFROMRX: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_RXCPIN; break; + case CLOCK_INT: flags = HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG; break; + case CLOCK_TXINT: flags = HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_TXC_BRG; break; + case CLOCK_DEFAULT: flags = info->params.flags & + (HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); break; + default: return -EINVAL; + } + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + info->params.flags &= ~(HDLC_FLAG_RXC_RXCPIN | HDLC_FLAG_RXC_DPLL | + HDLC_FLAG_RXC_BRG | HDLC_FLAG_RXC_TXCPIN | + HDLC_FLAG_TXC_TXCPIN | HDLC_FLAG_TXC_DPLL | + HDLC_FLAG_TXC_BRG | HDLC_FLAG_TXC_RXCPIN); + info->params.flags |= flags; + + info->params.loopback = new_line.loopback; + + if (flags & (HDLC_FLAG_RXC_BRG | HDLC_FLAG_TXC_BRG)) + info->params.clock_speed = new_line.clock_rate; + else + info->params.clock_speed = 0; + + /* if network interface up, reprogram hardware */ + if (info->netcount) + mgslpc_program_hw(info); + return 0; + + default: + return hdlc_ioctl(dev, ifr, cmd); + } } -int mgslpc_sppp_close(struct net_device *d) +/** + * called by network layer when transmit timeout is detected + * + * dev pointer to network device structure + */ +static void hdlcdev_tx_timeout(struct net_device *dev) { - MGSLPC_INFO *info = d->priv; + MGSLPC_INFO *info = dev_to_port(dev); + struct net_device_stats *stats = hdlc_stats(dev); unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_close(%s)\n",info->netname); + printk("hdlcdev_tx_timeout(%s)\n",dev->name); - /* shutdown adapter and release resources */ - shutdown(info); + stats->tx_errors++; + stats->tx_aborted_errors++; - /* allow syncppp to do close processing */ - sppp_close(d); - netif_stop_queue(d); + spin_lock_irqsave(&info->lock,flags); + tx_stop(info); + spin_unlock_irqrestore(&info->lock,flags); - spin_lock_irqsave(&info->netlock, flags); - info->netcount=0; - spin_unlock_irqrestore(&info->netlock, flags); - return 0; + netif_wake_queue(dev); } -void mgslpc_sppp_rx_done(MGSLPC_INFO *info, char *buf, int size) +/** + * called by device driver when transmit completes + * reenable network layer transmit if stopped + * + * info pointer to device instance information + */ +static void hdlcdev_tx_done(MGSLPC_INFO *info) +{ + if (netif_queue_stopped(info->netdev)) + netif_wake_queue(info->netdev); +} + +/** + * called by device driver when frame received + * pass frame to network layer + * + * info pointer to device instance information + * buf pointer to buffer contianing frame data + * size count of data bytes in buf + */ +static void hdlcdev_rx(MGSLPC_INFO *info, char *buf, int size) { struct sk_buff *skb = dev_alloc_skb(size); + struct net_device *dev = info->netdev; + struct net_device_stats *stats = hdlc_stats(dev); + if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_sppp_rx_done(%s)\n",info->netname); + printk("hdlcdev_rx(%s)\n",dev->name); + if (skb == NULL) { - printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", - info->netname); - info->netstats.rx_dropped++; + printk(KERN_NOTICE "%s: can't alloc skb, dropping packet\n", dev->name); + stats->rx_dropped++; return; } memcpy(skb_put(skb, size),buf,size); - skb->protocol = htons(ETH_P_WAN_PPP); - skb->dev = info->netdev; - skb->mac.raw = skb->data; - info->netstats.rx_packets++; - info->netstats.rx_bytes += size; + skb->protocol = hdlc_type_trans(skb, info->netdev); + + stats->rx_packets++; + stats->rx_bytes += size; + netif_rx(skb); - info->netdev->trans_start = jiffies; -} -void mgslpc_sppp_tx_done(MGSLPC_INFO *info) -{ - if (netif_queue_stopped(info->netdev)) - netif_wake_queue(info->netdev); + info->netdev->last_rx = jiffies; } -struct net_device_stats *mgslpc_net_stats(struct net_device *dev) +/** + * called by device driver when adding device instance + * do generic HDLC initialization + * + * info pointer to device instance information + * + * returns 0 if success, otherwise error code + */ +static int hdlcdev_init(MGSLPC_INFO *info) { - MGSLPC_INFO *info = dev->priv; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("mgslpc_net_stats(%s)\n",info->netname); - return &info->netstats; + int rc; + struct net_device *dev; + hdlc_device *hdlc; + + /* allocate and initialize network and HDLC layer objects */ + + if (!(dev = alloc_hdlcdev(info))) { + printk(KERN_ERR "%s:hdlc device allocation failure\n",__FILE__); + return -ENOMEM; + } + + /* for network layer reporting purposes only */ + dev->base_addr = info->io_base; + dev->irq = info->irq_level; + + /* network layer callbacks and settings */ + dev->do_ioctl = hdlcdev_ioctl; + dev->open = hdlcdev_open; + dev->stop = hdlcdev_close; + dev->tx_timeout = hdlcdev_tx_timeout; + dev->watchdog_timeo = 10*HZ; + dev->tx_queue_len = 50; + + /* generic HDLC layer callbacks and settings */ + hdlc = dev_to_hdlc(dev); + hdlc->attach = hdlcdev_attach; + hdlc->xmit = hdlcdev_xmit; + + /* register objects with HDLC layer */ + if ((rc = register_hdlc_device(dev))) { + printk(KERN_WARNING "%s:unable to register hdlc device\n",__FILE__); + free_netdev(dev); + return rc; + } + + info->netdev = dev; + return 0; } -int mgslpc_sppp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +/** + * called by device driver when removing device instance + * do generic HDLC cleanup + * + * info pointer to device instance information + */ +static void hdlcdev_exit(MGSLPC_INFO *info) { - MGSLPC_INFO *info = dev->priv; - if (debug_level >= DEBUG_LEVEL_INFO) - printk("%s(%d):mgslpc_ioctl %s cmd=%08X\n", __FILE__,__LINE__, - info->netname, cmd ); - return sppp_do_ioctl(dev, ifr, cmd); + unregister_hdlc_device(info->netdev); + free_netdev(info->netdev); + info->netdev = NULL; } -#endif /* ifdef CONFIG_SYNCLINK_SYNCPPP */ +#endif /* CONFIG_HDLC */ +