/*
* 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.22 2004/06/01 20:27:46 paulkf Exp $
*
* Device driver for Microgate SyncLink PC Card
* multiprotocol serial adapter.
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);
+static int wait_events(MGSLPC_INFO *info, int __user *mask);
#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
MODULE_LICENSE("GPL");
static char *driver_name = "SyncLink PC Card driver";
-static char *driver_version = "$Revision: 4.21 $";
+static char *driver_version = "$Revision: 4.22 $";
static struct tty_driver *serial_driver;
* (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;
+}
static dev_link_t *mgslpc_attach(void)
{
/* 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)
/* 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)
*
* 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;
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)
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)
* 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;
{
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:
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);
.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);
+
+ /* 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);
+ }
+}
+
static int __init synclink_cs_init(void)
{
- int error;
+ int rc;
if (break_on_load) {
mgslpc_get_text_ptr();
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 */
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);