summaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-10-05 14:55:46 +0100
committerDavid Howells <dhowells@warthog.cambridge.redhat.com>2006-10-05 15:10:12 +0100
commit7d12e780e003f93433d49ce78cfedf4b4c52adc5 (patch)
tree6748550400445c11a306b132009f3001e3525df8 /include/linux
parentda482792a6d1a3fbaaa25fae867b343fb4db3246 (diff)
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/adb.h4
-rw-r--r--include/linux/arcdevice.h2
-rw-r--r--include/linux/hiddev.h4
-rw-r--r--include/linux/ide.h2
-rw-r--r--include/linux/input.h7
-rw-r--r--include/linux/interrupt.h4
-rw-r--r--include/linux/ioc3.h2
-rw-r--r--include/linux/irq.h40
-rw-r--r--include/linux/libata.h4
-rw-r--r--include/linux/parport.h16
-rw-r--r--include/linux/profile.h2
-rw-r--r--include/linux/rtc.h2
-rw-r--r--include/linux/serial_core.h7
-rw-r--r--include/linux/serio.h5
-rw-r--r--include/linux/sysrq.h6
-rw-r--r--include/linux/usb.h3
-rw-r--r--include/linux/usb/serial.h12
17 files changed, 50 insertions, 72 deletions
diff --git a/include/linux/adb.h b/include/linux/adb.h
index b7305b17827..64d8878e144 100644
--- a/include/linux/adb.h
+++ b/include/linux/adb.h
@@ -90,10 +90,10 @@ extern struct blocking_notifier_head adb_client_list;
int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
int flags, int nbytes, ...);
int adb_register(int default_id,int handler_id,struct adb_ids *ids,
- void (*handler)(unsigned char *, int, struct pt_regs *, int));
+ void (*handler)(unsigned char *, int, int));
int adb_unregister(int index);
void adb_poll(void);
-void adb_input(unsigned char *, int, struct pt_regs *, int);
+void adb_input(unsigned char *, int, int);
int adb_reset_bus(void);
int adb_try_handler_change(int address, int new_id);
diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h
index 231ba090ae3..2f85049cfb3 100644
--- a/include/linux/arcdevice.h
+++ b/include/linux/arcdevice.h
@@ -334,7 +334,7 @@ void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc);
#endif
void arcnet_unregister_proto(struct ArcProto *proto);
-irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t arcnet_interrupt(int irq, void *dev_id);
struct net_device *alloc_arcdev(char *name);
#endif /* __KERNEL__ */
diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h
index 945ba1ad14a..acbdae6d7ae 100644
--- a/include/linux/hiddev.h
+++ b/include/linux/hiddev.h
@@ -222,7 +222,7 @@ struct hid_report;
int hiddev_connect(struct hid_device *);
void hiddev_disconnect(struct hid_device *);
void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value, struct pt_regs *regs);
+ struct hid_usage *usage, __s32 value);
void hiddev_report_event(struct hid_device *hid, struct hid_report *report);
int __init hiddev_init(void);
void hiddev_exit(void);
@@ -230,7 +230,7 @@ void hiddev_exit(void);
static inline int hiddev_connect(struct hid_device *hid) { return -1; }
static inline void hiddev_disconnect(struct hid_device *hid) { }
static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value, struct pt_regs *regs) { }
+ struct hid_usage *usage, __s32 value) { }
static inline void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { }
static inline int hiddev_init(void) { return 0; }
static inline void hiddev_exit(void) { }
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 07d8d725541..9c2050293f1 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -1185,7 +1185,7 @@ extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
extern int ide_spin_wait_hwgroup(ide_drive_t *);
extern void ide_timer_expiry(unsigned long);
-extern irqreturn_t ide_intr(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t ide_intr(int irq, void *dev_id);
extern void do_ide_request(request_queue_t *);
void ide_init_disk(struct gendisk *, ide_drive_t *);
diff --git a/include/linux/input.h b/include/linux/input.h
index 5770105471d..c38507ba38b 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -953,7 +953,6 @@ struct input_dev {
unsigned int repeat_key;
struct timer_list timer;
- struct pt_regs *regs;
int state;
int sync;
@@ -1149,15 +1148,9 @@ static inline void input_report_switch(struct input_dev *dev, unsigned int code,
input_event(dev, EV_SW, code, !!value);
}
-static inline void input_regs(struct input_dev *dev, struct pt_regs *regs)
-{
- dev->regs = regs;
-}
-
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
- dev->regs = NULL;
}
static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index 19782350dcc..5b83e7b5962 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -64,7 +64,7 @@
#define SA_TRIGGER_RISING IRQF_TRIGGER_RISING
#define SA_TRIGGER_MASK IRQF_TRIGGER_MASK
-typedef irqreturn_t (*irq_handler_t)(int, void *, struct pt_regs *);
+typedef irqreturn_t (*irq_handler_t)(int, void *);
struct irqaction {
irq_handler_t handler;
@@ -77,7 +77,7 @@ struct irqaction {
struct proc_dir_entry *dir;
};
-extern irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t no_action(int cpl, void *dev_id);
extern int request_irq(unsigned int, irq_handler_t handler,
unsigned long, const char *, void *);
extern void free_irq(unsigned int, void *);
diff --git a/include/linux/ioc3.h b/include/linux/ioc3.h
index da7c09e4ede..38b286e9a46 100644
--- a/include/linux/ioc3.h
+++ b/include/linux/ioc3.h
@@ -63,7 +63,7 @@ struct ioc3_submodule {
/* IRQ stuff */
unsigned int irq_mask; /* IOC3 IRQ mask, leave clear for Ethernet */
int reset_mask; /* non-zero if you want the ioc3.c module to reset interrupts */
- int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int, struct pt_regs *);
+ int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
/* private submodule data */
void *data; /* assigned by submodule */
};
diff --git a/include/linux/irq.h b/include/linux/irq.h
index b947d46e4b1..c64f3cc7e87 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -21,11 +21,11 @@
#include <asm/irq.h>
#include <asm/ptrace.h>
+#include <asm/irq_regs.h>
struct irq_desc;
typedef void fastcall (*irq_flow_handler_t)(unsigned int irq,
- struct irq_desc *desc,
- struct pt_regs *regs);
+ struct irq_desc *desc);
/*
@@ -258,28 +258,18 @@ static inline int select_smp_affinity(unsigned int irq)
extern int no_irq_affinity;
/* Handle irq action chains: */
-extern int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
- struct irqaction *action);
+extern int handle_IRQ_event(unsigned int irq, struct irqaction *action);
/*
* Built-in IRQ handlers for various IRQ types,
* callable via desc->chip->handle_irq()
*/
-extern void fastcall
-handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
-extern void fastcall
-handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs);
-extern void fastcall
-handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
-extern void fastcall
-handle_simple_irq(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs);
-extern void fastcall
-handle_percpu_irq(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs);
-extern void fastcall
-handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
+extern void fastcall handle_level_irq(unsigned int irq, struct irq_desc *desc);
+extern void fastcall handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc);
+extern void fastcall handle_edge_irq(unsigned int irq, struct irq_desc *desc);
+extern void fastcall handle_simple_irq(unsigned int irq, struct irq_desc *desc);
+extern void fastcall handle_percpu_irq(unsigned int irq, struct irq_desc *desc);
+extern void fastcall handle_bad_irq(unsigned int irq, struct irq_desc *desc);
/*
* Get a descriptive string for the highlevel handler, for
@@ -292,7 +282,7 @@ extern const char *handle_irq_name(irq_flow_handler_t handle);
* (is an explicit fastcall, because i386 4KSTACKS calls it from assembly)
*/
#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
-extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
+extern fastcall unsigned int __do_IRQ(unsigned int irq);
#endif
/*
@@ -301,23 +291,23 @@ extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
* irqchip-style controller then we call the ->handle_irq() handler,
* and it calls __do_IRQ() if it's attached to an irqtype-style controller.
*/
-static inline void generic_handle_irq(unsigned int irq, struct pt_regs *regs)
+static inline void generic_handle_irq(unsigned int irq)
{
struct irq_desc *desc = irq_desc + irq;
#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
- desc->handle_irq(irq, desc, regs);
+ desc->handle_irq(irq, desc);
#else
if (likely(desc->handle_irq))
- desc->handle_irq(irq, desc, regs);
+ desc->handle_irq(irq, desc);
else
- __do_IRQ(irq, regs);
+ __do_IRQ(irq);
#endif
}
/* Handling of unhandled and spurious interrupts: */
extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
- int action_ret, struct pt_regs *regs);
+ int action_ret);
/* Resending of interrupts :*/
void check_irq_resend(struct irq_desc *desc, unsigned int irq);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index d1af1dbeaeb..d0a7ad5ed51 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -628,7 +628,7 @@ struct ata_port_operations {
void (*error_handler) (struct ata_port *ap);
void (*post_internal_cmd) (struct ata_queued_cmd *qc);
- irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
+ irq_handler_t irq_handler;
void (*irq_clear) (struct ata_port *);
u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
@@ -769,7 +769,7 @@ extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
extern int ata_port_start (struct ata_port *ap);
extern void ata_port_stop (struct ata_port *ap);
extern void ata_host_stop (struct ata_host *host);
-extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+extern irqreturn_t ata_interrupt (int irq, void *dev_instance);
extern void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data);
extern void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
diff --git a/include/linux/parport.h b/include/linux/parport.h
index 5bf321e82c9..80682aaa8f1 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -229,7 +229,7 @@ struct pardevice {
int (*preempt)(void *);
void (*wakeup)(void *);
void *private;
- void (*irq_func)(int, void *, struct pt_regs *);
+ void (*irq_func)(int, void *);
unsigned int flags;
struct pardevice *next;
struct pardevice *prev;
@@ -375,7 +375,7 @@ extern void parport_put_port (struct parport *);
struct pardevice *parport_register_device(struct parport *port,
const char *name,
int (*pf)(void *), void (*kf)(void *),
- void (*irq_func)(int, void *, struct pt_regs *),
+ void (*irq_func)(int, void *),
int flags, void *handle);
/* parport_unregister unlinks a device from the chain. */
@@ -457,7 +457,7 @@ static __inline__ int parport_yield_blocking(struct pardevice *dev)
#define PARPORT_FLAG_EXCL (1<<1) /* EXCL driver registered. */
/* IEEE1284 functions */
-extern void parport_ieee1284_interrupt (int, void *, struct pt_regs *);
+extern void parport_ieee1284_interrupt (int, void *);
extern int parport_negotiate (struct parport *, int mode);
extern ssize_t parport_write (struct parport *, const void *buf, size_t len);
extern ssize_t parport_read (struct parport *, void *buf, size_t len);
@@ -502,8 +502,7 @@ extern void parport_daisy_fini (struct parport *port);
extern struct pardevice *parport_open (int devnum, const char *name,
int (*pf) (void *),
void (*kf) (void *),
- void (*irqf) (int, void *,
- struct pt_regs *),
+ void (*irqf) (int, void *),
int flags, void *handle);
extern void parport_close (struct pardevice *dev);
extern ssize_t parport_device_id (int devnum, char *buffer, size_t len);
@@ -512,13 +511,12 @@ extern void parport_daisy_deselect_all (struct parport *port);
extern int parport_daisy_select (struct parport *port, int daisy, int mode);
/* Lowlevel drivers _can_ call this support function to handle irqs. */
-static __inline__ void parport_generic_irq(int irq, struct parport *port,
- struct pt_regs *regs)
+static __inline__ void parport_generic_irq(int irq, struct parport *port)
{
- parport_ieee1284_interrupt (irq, port, regs);
+ parport_ieee1284_interrupt (irq, port);
read_lock(&port->cad_lock);
if (port->cad && port->cad->irq_func)
- port->cad->irq_func(irq, port->cad->private, regs);
+ port->cad->irq_func(irq, port->cad->private);
read_unlock(&port->cad_lock);
}
diff --git a/include/linux/profile.h b/include/linux/profile.h
index e633004ae05..acce53fd38b 100644
--- a/include/linux/profile.h
+++ b/include/linux/profile.h
@@ -17,7 +17,7 @@ struct notifier_block;
/* init basic kernel profiler */
void __init profile_init(void);
-void profile_tick(int, struct pt_regs *);
+void profile_tick(int);
void profile_hit(int, void *);
#ifdef CONFIG_PROC_FS
void create_prof_cpu_mask(struct proc_dir_entry *);
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index b89f0935705..09ff4c3e271 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -208,7 +208,7 @@ int rtc_register(rtc_task_t *task);
int rtc_unregister(rtc_task_t *task);
int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
void rtc_get_rtc_time(struct rtc_time *rtc_tm);
-irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t rtc_interrupt(int irq, void *dev_id);
#endif /* __KERNEL__ */
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index b661c19f3f7..463ab953b09 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -409,13 +409,12 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port);
* The following are helper functions for the low level drivers.
*/
static inline int
-uart_handle_sysrq_char(struct uart_port *port, unsigned int ch,
- struct pt_regs *regs)
+uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
{
#ifdef SUPPORT_SYSRQ
if (port->sysrq) {
if (ch && time_before(jiffies, port->sysrq)) {
- handle_sysrq(ch, regs, port->info->tty);
+ handle_sysrq(ch, port->info->tty);
port->sysrq = 0;
return 1;
}
@@ -425,7 +424,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch,
return 0;
}
#ifndef SUPPORT_SYSRQ
-#define uart_handle_sysrq_char(port,ch,regs) uart_handle_sysrq_char(port, 0, NULL)
+#define uart_handle_sysrq_char(port,ch) uart_handle_sysrq_char(port, 0)
#endif
/*
diff --git a/include/linux/serio.h b/include/linux/serio.h
index c9069310b6a..3a697cc6eca 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -60,8 +60,7 @@ struct serio_driver {
unsigned int manual_bind;
void (*write_wakeup)(struct serio *);
- irqreturn_t (*interrupt)(struct serio *, unsigned char,
- unsigned int, struct pt_regs *);
+ irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int);
int (*connect)(struct serio *, struct serio_driver *drv);
int (*reconnect)(struct serio *);
void (*disconnect)(struct serio *);
@@ -75,7 +74,7 @@ int serio_open(struct serio *serio, struct serio_driver *drv);
void serio_close(struct serio *serio);
void serio_rescan(struct serio *serio);
void serio_reconnect(struct serio *serio);
-irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
+irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags);
void __serio_register_port(struct serio *serio, struct module *owner);
static inline void serio_register_port(struct serio *serio)
diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h
index e657e523b9b..9df8833670c 100644
--- a/include/linux/sysrq.h
+++ b/include/linux/sysrq.h
@@ -29,7 +29,7 @@ struct tty_struct;
#define SYSRQ_ENABLE_RTNICE 0x0100
struct sysrq_key_op {
- void (*handler)(int, struct pt_regs *, struct tty_struct *);
+ void (*handler)(int, struct tty_struct *);
char *help_msg;
char *action_msg;
int enable_mask;
@@ -42,8 +42,8 @@ struct sysrq_key_op {
* are available -- else NULL's).
*/
-void handle_sysrq(int, struct pt_regs *, struct tty_struct *);
-void __handle_sysrq(int, struct pt_regs *, struct tty_struct *, int check_mask);
+void handle_sysrq(int, struct tty_struct *);
+void __handle_sysrq(int, struct tty_struct *, int check_mask);
int register_sysrq_key(int, struct sysrq_key_op *);
int unregister_sysrq_key(int, struct sysrq_key_op *);
struct sysrq_key_op *__sysrq_get_key_op(int key);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 190cc1b78fe..5482bfb3303 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -764,9 +764,8 @@ struct usb_iso_packet_descriptor {
};
struct urb;
-struct pt_regs;
-typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
+typedef void (*usb_complete_t)(struct urb *);
/**
* struct urb - USB Request Block
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 91c983eef89..91b3ea2bbb1 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -226,10 +226,10 @@ struct usb_serial_driver {
int (*tiocmget) (struct usb_serial_port *port, struct file *file);
int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
- void (*read_int_callback)(struct urb *urb, struct pt_regs *regs);
- void (*write_int_callback)(struct urb *urb, struct pt_regs *regs);
- void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs);
- void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs);
+ void (*read_int_callback)(struct urb *urb);
+ void (*write_int_callback)(struct urb *urb);
+ void (*read_bulk_callback)(struct urb *urb);
+ void (*write_bulk_callback)(struct urb *urb);
};
#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver)
@@ -262,8 +262,8 @@ extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigne
extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
extern int usb_serial_generic_write_room (struct usb_serial_port *port);
extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port);
-extern void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
-extern void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
+extern void usb_serial_generic_read_bulk_callback (struct urb *urb);
+extern void usb_serial_generic_write_bulk_callback (struct urb *urb);
extern void usb_serial_generic_shutdown (struct usb_serial *serial);
extern int usb_serial_generic_register (int debug);
extern void usb_serial_generic_deregister (void);