00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include "config/config.h"
00023 #endif
00024 #include <linux/module.h>
00025 #include <linux/pci.h>
00026 #include <linux/list.h>
00027 #include <linux/ioport.h>
00028 #include <linux/irq.h>
00029 #include <linux/moduleparam.h>
00030 #include <linux/rwsem.h>
00031 #include <linux/proc_fs.h>
00032 #include <asm/atomic.h>
00033
00034 #include "most-constants.h"
00035 #include "most-base.h"
00036 #include "most-common.h"
00037
00038 #ifdef RT_RTDM
00039 # include <rtdm/rtdm_driver.h>
00040 # include "most-common-rt.h"
00041 #endif
00042
00052 #define DRIVER_NAME "most-base"
00053
00057 #define PR DRIVER_NAME ": "
00058
00062 static char *version = "$Rev: 639 $";
00063
00067 RWSEMA_LOCKED_LIST(most_base_low_drivers);
00068
00072 RWSEMA_LOCKED_LIST(most_base_high_drivers_sema);
00073
00077 SPIN_LOCKED_LIST(most_base_high_drivers_spin);
00078
00082 static dev_t major_id = 0;
00083
00087 static atomic_t device_count = ATOMIC_INIT(0);
00088
00089
00090
00091
00092
00093 int most_register_high_driver(struct most_high_driver *driver)
00094 {
00095 struct list_head *cursor;
00096 struct most_low_driver *low_driver;
00097 rtnrt_lockctx_t flags;
00098
00099
00100 down_write(&most_base_high_drivers_sema.lock);
00101 list_add_tail(&driver->sema_list, &most_base_high_drivers_sema.list);
00102 up_write(&most_base_high_drivers_sema.lock);
00103
00104
00105 rtnrt_lock_get_irqsave(&most_base_high_drivers_spin.lock, flags);
00106 list_add_tail(&driver->spin_list, &most_base_high_drivers_spin.list);
00107 rtnrt_lock_put_irqrestore(&most_base_high_drivers_spin.lock, flags);
00108
00109
00110
00111
00112
00113 down_read(&most_base_low_drivers.lock);
00114 list_for_each(cursor, &most_base_low_drivers.list) {
00115 low_driver = list_entry(cursor, struct most_low_driver, list);
00116 low_driver->high_driver_registered(driver);
00117 }
00118 up_read(&most_base_low_drivers.lock);
00119
00120 return 0;
00121 }
00122
00123
00124
00125
00126
00127 void most_deregister_high_driver(struct most_high_driver *driver)
00128 {
00129 struct list_head *cursor_low_driver;
00130 struct most_low_driver *low_driver;
00131 rtnrt_lockctx_t flags;
00132
00133
00134 down_read(&most_base_low_drivers.lock);
00135 list_for_each(cursor_low_driver, &most_base_low_drivers.list) {
00136 low_driver = list_entry(cursor_low_driver, struct most_low_driver, list);
00137 low_driver->high_driver_deregistered(driver);
00138 }
00139 up_read(&most_base_low_drivers.lock);
00140
00141
00142 rtnrt_lock_get_irqsave(&most_base_high_drivers_spin.lock, flags);
00143 list_del(&driver->spin_list);
00144 rtnrt_lock_put_irqrestore(&most_base_high_drivers_spin.lock, flags);
00145
00146
00147 down_write(&most_base_high_drivers_sema.lock);
00148 list_del(&driver->sema_list);
00149 up_write(&most_base_high_drivers_sema.lock);
00150 }
00151
00152
00153
00154
00155 void most_register_low_driver(struct most_low_driver *driver)
00156 {
00157
00158 down_write(&most_base_low_drivers.lock);
00159 list_add_tail(&driver->list, &most_base_low_drivers.list);
00160 up_write(&most_base_low_drivers.lock);
00161 }
00162
00163
00164
00165
00166 void most_deregister_low_driver(struct most_low_driver *driver)
00167 {
00168
00169 down_write(&most_base_low_drivers.lock);
00170 list_del(&driver->list);
00171 up_write(&most_base_low_drivers.lock);
00172 }
00173
00174
00175
00176
00177
00178 struct most_dev *most_dev_new(void)
00179 {
00180 struct most_dev *ret;
00181
00182 ret = kmalloc(sizeof(struct most_dev), GFP_KERNEL);
00183 if (!ret) {
00184 return NULL;
00185 }
00186
00187 memset(ret, sizeof(struct most_dev), 0);
00188
00189 spin_lock_init(&ret->lock);
00190 INIT_LIST_HEAD(&ret->list);
00191 ret->major_device_no = MAJOR(major_id);
00192 ret->card_number = atomic_read(&device_count);
00193
00194 atomic_inc(&device_count);
00195 sprintf(ret->name, "most-%d", MOST_DEV_CARDNUMBER(ret));
00196
00197 return ret;
00198 }
00199
00200
00201
00202
00203 void most_dev_free(struct most_dev* dev)
00204 {
00205 atomic_dec(&device_count);
00206 if (dev->impl) {
00207 kfree(dev->impl);
00208 }
00209 kfree(dev);
00210 }
00211
00220 static void *most_base_seq_start(struct seq_file *s, loff_t *pos)
00221 {
00222 return *pos == 0
00223 ? &version
00224 : NULL;
00225 }
00226
00236 static void *most_base_seq_next(struct seq_file *s, void *v, loff_t *pos)
00237 {
00238 (*pos)++;
00239 return NULL;
00240 }
00241
00249 static void most_base_seq_stop(struct seq_file *sfile, void *v)
00250 {}
00251
00258 static int most_base_seq_show(struct seq_file *s, void *v)
00259 {
00260 struct list_head *cursor_low_driver;
00261 struct most_low_driver *low_driver;
00262
00263 seq_printf(s, ">> MOST for Linux <<\n\n");
00264 seq_printf(s, "Devices:\n");
00265
00266
00267 down_read(&most_base_low_drivers.lock);
00268 list_for_each(cursor_low_driver, &most_base_low_drivers.list) {
00269 low_driver = list_entry(cursor_low_driver, struct most_low_driver, list);
00270 if (low_driver->proc_show) {
00271 low_driver->proc_show(s);
00272 }
00273 }
00274 up_read(&most_base_low_drivers.lock);
00275
00276 return 0;
00277 }
00278
00282 static struct seq_operations most_base_seq_ops = {
00283 .start = most_base_seq_start,
00284 .next = most_base_seq_next,
00285 .stop = most_base_seq_stop,
00286 .show = most_base_seq_show
00287 };
00288
00295 static int most_base_proc_open(struct inode *inode, struct file *file)
00296 {
00297 return seq_open(file, &most_base_seq_ops);
00298 }
00299
00303 static struct file_operations most_base_proc_ops = {
00304 .owner = THIS_MODULE,
00305 .open = most_base_proc_open,
00306 .read = seq_read,
00307 .llseek = seq_lseek,
00308 .release = seq_release
00309 };
00310
00316 static int __init most_base_init(void)
00317 {
00318 int err;
00319 struct proc_dir_entry *entry;
00320
00321
00322 err = alloc_chrdev_region(&major_id, 0, MOST_MINOR_IDS, DRIVER_NAME);
00323 if (unlikely(err != 0)) {
00324 rtnrt_err("Error in alloc_chrdev_region, err = %d\n", err);
00325 return err;
00326 }
00327 rtnrt_info("Registered major id %d\n", MAJOR(major_id));
00328
00329
00330 entry = create_proc_entry("most", 0, NULL);
00331 if (likely(entry)) {
00332 entry->proc_fops = &most_base_proc_ops;
00333 }
00334
00335 return 0;
00336 }
00337
00338
00342 static void __exit most_base_exit(void)
00343 {
00344 rtnrt_info("Unloading module %s, version %s\n", DRIVER_NAME, version);
00345
00346
00347 unregister_chrdev_region(major_id, MOST_MINOR_IDS);
00348
00349
00350 remove_proc_entry("most", NULL);
00351 }
00352
00353 #ifndef DOXYGEN
00354 EXPORT_SYMBOL(most_register_high_driver);
00355 EXPORT_SYMBOL(most_deregister_high_driver);
00356 EXPORT_SYMBOL(most_register_low_driver);
00357 EXPORT_SYMBOL(most_deregister_low_driver);
00358 EXPORT_SYMBOL(most_base_high_drivers_sema);
00359 EXPORT_SYMBOL(most_base_high_drivers_spin);
00360 EXPORT_SYMBOL(most_dev_new);
00361 EXPORT_SYMBOL(most_dev_free);
00362
00363 MODULE_LICENSE("GPL");
00364 MODULE_AUTHOR("Bernhard Walle");
00365 MODULE_VERSION("$Rev: 639 $");
00366 MODULE_DESCRIPTION("Base driver for the MOST devices from OASIS Silicon systems.");
00367 module_init(most_base_init);
00368 module_exit(most_base_exit);
00369 #endif
00370
00371