static void serial_close (struct tty_struct *tty, struct file *filp) { unsigned long flags; struct serproto_dev *device; int uc; uc = GET_USE_COUNT (THIS_MODULE); dbg_oc (3, "tty #%p file #%p uc=%d", tty, filp, uc); if ((device = tty->driver_data) != NULL) { write_lock_irqsave (&device->rwlock, flags); if (0 >= --device->opencnt) { // Last (or extra) close dbg_oc (1, "Last: old tty #%p new #%p oc=%d", device->tty, tty, device->opencnt); tty->driver_data = NULL; device->tty = NULL; device->opencnt = 0; } write_unlock_irqrestore (&device->rwlock, flags); } else { dbg_oc (1, "not presently connected"); } if (uc > 0) { // Should really check that uc hasn't changed since start of fn... MOD_DEC_USE_COUNT; dbg_init (1, "CLOSE uc=%d", GET_USE_COUNT (THIS_MODULE)); } dbg_oc (3, "OK"); return; }
/* * usbd_pm_callback * @dev: * @rqst: * @unused: * * Used to signal power management events. */ static int bi_pm_event (struct pm_dev *pm_dev, pm_request_t request, void *unused) { struct usb_device_instance *device; dbg_pm (0, "request: %d pm_dev: %p data: %p", request, pm_dev, pm_dev->data); if (!(device = pm_dev->data)) { dbg_pm (0, "DATA NULL, NO DEVICE"); return 0; } switch (request) { #if defined(CONFIG_IRIS) case PM_STANDBY: case PM_BLANK: #endif case PM_SUSPEND: dbg_pm (0, "PM_SUSPEND"); if (!pm_suspended) { pm_suspended = 1; dbg_init (1, "MOD_INC_USE_COUNT %d", GET_USE_COUNT (THIS_MODULE)); udc_disconnect (); // disable USB pullup if we can udc_disable_interrupts (device); // disable interupts udc_disable (); // disable UDC dbg_pm (0, "PM_SUSPEND: finished"); } break; #if defined(CONFIG_IRIS) case PM_UNBLANK: #endif case PM_RESUME: dbg_pm (0, "PM_RESUME"); if (pm_suspended) { // probe for device if (udc_init ()) { dbg_init (0, "udc_init failed"); //return -EINVAL; } udc_enable (device); // enable UDC udc_all_interrupts (device); // enable interrupts udc_connect (); // enable USB pullup if we can //udc_set_address(device->address); //udc_reset_ep(0); pm_suspended = 0; dbg_init (1, "MOD_INC_USE_COUNT %d", GET_USE_COUNT (THIS_MODULE)); dbg_pm (0, "PM_RESUME: finished"); } break; } return 0; }
/* * * serial_open - open serial device * @tty: tty device * @filp: file structure * * Called to open serial device. */ static int serial_open (struct tty_struct *tty, struct file *filp) { unsigned long flags; int n = 0, rc = 0; struct serproto_dev *device = NULL; dbg_oc (3, "tty #%p file #%p", tty, filp); if (NULL == tty || 0 > (n = MINOR (tty->device) - tty->driver.minor_start) || n >= serproto_devices || NULL == (device = serproto_device_array[n])) { dbg_oc (1, "FAIL ENODEV"); return -ENODEV; } MOD_INC_USE_COUNT; dbg_init (1, "OPEN uc=%d", GET_USE_COUNT (THIS_MODULE)); write_lock_irqsave (&device->rwlock, flags); if (1 == ++device->opencnt) { // First open tty->driver_data = device; device->tty = tty; tty->low_latency = 1; /* force low_latency on so that our tty_push actually forces the data through, * otherwise it is scheduled, and with high data rates (like with OHCI) data * can get lost. * */ tty->low_latency = 1; } else if (tty->driver_data != device || device->tty != tty) { // Second or later open, different tty/device combo rc = -EBUSY; } // XXX Should extract info from somewhere to see if receive is OK write_unlock_irqrestore (&device->rwlock, flags); if (0 != rc) { if (-EBUSY == rc) { dbg_oc (1, "2nd, conflict: old dev #%p new #%p, old tty #%p new #%p", tty->driver_data, device, device->tty, tty); } MOD_DEC_USE_COUNT; dbg_init (0, "OPEN rc=%d uc=%d", rc, GET_USE_COUNT (THIS_MODULE)); } dbg_oc (3, "->%d n=%d", rc, n); return (rc); }
static int bi_udc_resume(struct device *dev, u32 level) { int ret = 0; struct usb_device_instance *device = device_array[0]; switch (level) { case RESUME_POWER_ON: dbg_pm (0, "RESUME_POWER_ON"); if (udc_init ()) { dbg_init (0, "udc_init failed"); } if (device) { udc_enable (device); /* enable UDC */ udc_all_interrupts (device); /* enable interrupts */ } udc_connect (); /* enable USB pullup */ dbg_init (1, "MOD_INC_USE_COUNT %d", GET_USE_COUNT (THIS_MODULE)); dbg_pm (0, "RESUME_POWER_ON: finished"); break; } return ret; }
void capiminor_free(struct capiminor *mp) { struct capiminor **pp; pp = &minors; while (*pp) { if (*pp == mp) { *pp = (*pp)->next; if (mp->ttyskb) kfree_skb(mp->ttyskb); mp->ttyskb = 0; skb_queue_purge(&mp->recvqueue); skb_queue_purge(&mp->inqueue); skb_queue_purge(&mp->outqueue); capiminor_del_all_ack(mp); kmem_cache_free(capiminor_cachep, mp); MOD_DEC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(THIS_MODULE)); #endif return; } else { pp = &(*pp)->next; } } }
int capinc_tty_open(struct tty_struct * tty, struct file * file) { struct capiminor *mp; if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0) return -ENXIO; if (mp->nccip == 0) return -ENXIO; if (mp->file) return -EBUSY; skb_queue_head_init(&mp->recvqueue); init_waitqueue_head(&mp->recvwait); init_waitqueue_head(&mp->sendwait); tty->driver_data = (void *)mp; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_tty_open %d\n", GET_USE_COUNT(THIS_MODULE)); #endif if (atomic_read(&mp->ttyopencount) == 0) mp->tty = tty; atomic_inc(&mp->ttyopencount); #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_tty_open ocount=%d\n", atomic_read(&mp->ttyopencount)); #endif handle_minor_recv(mp); return 0; }
/* * Try to free modules which have been marked for deletion. Returns nonzero * if a module was actually freed. */ int free_modules( void) { struct module *mp; struct module **mpp; int did_deletion; did_deletion = 0; freeing_modules = 0; mpp = &module_list; while ((mp = *mpp) != NULL) { if (mp->state != MOD_DELETED) { mpp = &mp->next; } else { if ((GET_USE_COUNT(mp) != 0) || (mp->ref != NULL)) { freeing_modules = 1; mpp = &mp->next; } else { /* delete it */ *mpp = mp->next; if (mp->symtab) { if (mp->symtab->n_refs) drop_refs(mp); if (mp->symtab->size) kfree_s(mp->symtab, mp->symtab->size); } vfree(mp->addr); kfree_s(mp, sizeof(struct module) + MOD_MAX_NAME); did_deletion = 1; } } } return did_deletion; }
/* * Try to free modules which have been marked for deletion. Returns nonzero * if a module was actually freed. */ int free_modules( void) { struct module *mp; struct module **mpp; int did_deletion; did_deletion = 0; freeing_modules = 0; mpp = &module_list; while ((mp = *mpp) != NULL) { if (mp->state != MOD_DELETED) { mpp = &mp->next; } else if (GET_USE_COUNT(mp) != 0) { freeing_modules = 1; mpp = &mp->next; } else { /* delete it */ *mpp = mp->next; vfree(mp->addr); kfree(mp->name); kfree_s(mp, sizeof *mp); did_deletion = 1; } } return did_deletion; }
static int capi_open(struct inode *inode, struct file *file) { if (file->private_data) return -EEXIST; if ((file->private_data = capidev_alloc(file)) == 0) return -ENOMEM; MOD_INC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(THIS_MODULE)); #endif return 0; }
static int capi_release(struct inode *inode, struct file *file) { struct capidev *cdev = (struct capidev *)file->private_data; lock_kernel(); capincci_free(cdev, 0xffffffff); capidev_free(cdev); file->private_data = NULL; MOD_DEC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE)); #endif unlock_kernel(); return 0; }
static int capinc_raw_release(struct inode *inode, struct file *file) { struct capiminor *mp = (struct capiminor *)file->private_data; if (mp) { lock_kernel(); mp->file = 0; if (mp->nccip == 0) { capiminor_free(mp); file->private_data = NULL; } unlock_kernel(); } #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capinc_raw_release %d\n", GET_USE_COUNT(THIS_MODULE)); #endif return 0; }
static int bi_udc_suspend(struct device *dev, u32 state, u32 level) { struct usb_device_instance *device = device_array[0]; switch (level) { case SUSPEND_POWER_DOWN: dbg_pm (0, "SUSPEND_POWER_DOWN"); dbg_init (1, "MOD_INC_USE_COUNT %d", GET_USE_COUNT (THIS_MODULE)); udc_disconnect (); /* disable USB pullup */ if (device) udc_disable_interrupts (device); /* disable interrupts */ udc_disable (); /* disable UDC */ dbg_pm (0, "SUSPEND_POWER_DOWN: finished"); break; } return 0; }
struct capiminor *capiminor_alloc(__u16 applid, __u32 ncci) { struct capiminor *mp, **pp; unsigned int minor = 0; MOD_INC_USE_COUNT; mp = (struct capiminor *)kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC); if (!mp) { MOD_DEC_USE_COUNT; printk(KERN_ERR "capi: can't alloc capiminor\n"); return 0; } #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capiminor_alloc %d\n", GET_USE_COUNT(THIS_MODULE)); #endif memset(mp, 0, sizeof(struct capiminor)); mp->applid = applid; mp->ncci = ncci; mp->msgid = 0; atomic_set(&mp->ttyopencount,0); skb_queue_head_init(&mp->inqueue); skb_queue_head_init(&mp->outqueue); skb_queue_head_init(&mp->recvqueue); init_waitqueue_head(&mp->recvwait); init_waitqueue_head(&mp->sendwait); for (pp = &minors; *pp; pp = &(*pp)->next) { if ((*pp)->minor < minor) continue; if ((*pp)->minor > minor) break; minor++; } mp->minor = minor; mp->next = *pp; *pp = mp; return mp; }
asmlinkage int sys_delete_module(char *module_name) { struct module *mp; char name[MOD_MAX_NAME]; int error; if (!suser()) return -EPERM; /* else */ if (module_name != NULL) { if ((error = get_mod_name(module_name, name)) != 0) return error; if ((mp = find_module(name)) == NULL) return -ENOENT; if ((mp->ref != NULL) || ((GET_USE_COUNT(mp) & ~(MOD_AUTOCLEAN | MOD_VISITED)) != 0)) return -EBUSY; GET_USE_COUNT(mp) &= ~(MOD_AUTOCLEAN | MOD_VISITED); if (mp->state == MOD_RUNNING) (*mp->cleanup)(); mp->state = MOD_DELETED; free_modules(); } /* for automatic reaping */ else { struct module *mp_next; for (mp = module_list; mp != &kernel_module; mp = mp_next) { mp_next = mp->next; if ((mp->ref == NULL) && (mp->state == MOD_RUNNING) && ((GET_USE_COUNT(mp) & ~MOD_VISITED) == MOD_AUTOCLEAN)) { if ((GET_USE_COUNT(mp) & MOD_VISITED)) { /* Don't reap until one "cycle" after last _use_ */ GET_USE_COUNT(mp) &= ~MOD_VISITED; } else { GET_USE_COUNT(mp) &= ~(MOD_AUTOCLEAN | MOD_VISITED); (*mp->cleanup)(); mp->state = MOD_DELETED; free_modules(); } } } } return 0; }
static int capinc_raw_open(struct inode *inode, struct file *file) { struct capiminor *mp; if (file->private_data) return -EEXIST; if ((mp = capiminor_find(MINOR(file->f_dentry->d_inode->i_rdev))) == 0) return -ENXIO; if (mp->nccip == 0) return -ENXIO; if (mp->file) return -EBUSY; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_raw_open %d\n", GET_USE_COUNT(THIS_MODULE)); #endif mp->datahandle = 0; mp->file = file; file->private_data = (void *)mp; handle_minor_recv(mp); return 0; }
/* Called by modules package before trying to unload the module */ static int can_unload(void) { return (GET_USE_COUNT(THIS_MODULE)||zft_dirty()||busy_flag)?-EBUSY:0; }
/* * Called by the /proc file system to return a current list of modules. */ int get_module_list(char *buf) { char *p; const char *q; int i; struct module *mp; struct module_ref *ref; char size[32]; p = buf; /* Do not show the kernel pseudo module */ for (mp = module_list ; mp && mp->next; mp = mp->next) { if (p - buf > 4096 - 100) break; /* avoid overflowing buffer */ q = mp->name; if (*q == '\0' && mp->size == 0 && mp->ref == NULL) continue; /* don't list modules for kernel syms */ i = 20; while (*q) { *p++ = *q++; i--; } sprintf(size, "%d", mp->size); i -= strlen(size); if (i <= 0) i = 1; while (--i >= 0) *p++ = ' '; q = size; while (*q) *p++ = *q++; if (mp->state == MOD_UNINITIALIZED) q = " (uninitialized)"; else if (mp->state == MOD_RUNNING) q = ""; else if (mp->state == MOD_DELETED) q = " (deleted)"; else q = " (bad state)"; while (*q) *p++ = *q++; *p++ = '\t'; if ((ref = mp->ref) != NULL) { *p++ = '['; for (; ref; ref = ref->next) { q = ref->module->name; while (*q) *p++ = *q++; if (ref->next) *p++ = ' '; } *p++ = ']'; } if (mp->state == MOD_RUNNING) { sprintf(size,"\t%ld%s", GET_USE_COUNT(mp) & ~(MOD_AUTOCLEAN | MOD_VISITED), ((GET_USE_COUNT(mp) & MOD_AUTOCLEAN)? " (autoclean)":"")); q = size; while (*q) *p++ = *q++; } *p++ = '\n'; } return p - buf; }
/* * Initialize a module. */ asmlinkage int sys_init_module(char *module_name, char *code, unsigned codesize, struct mod_routines *routines, struct symbol_table *symtab) { struct module *mp; struct symbol_table *newtab; char name[MOD_MAX_NAME]; int error; struct mod_routines rt; if (!suser()) return -EPERM; #ifdef __i386__ /* A little bit of protection... we "know" where the user stack is... */ if (symtab && ((unsigned long)symtab > 0xb0000000)) { printk(KERN_WARNING "warning: you are using an old insmod, no symbols will be inserted!\n"); symtab = NULL; } #endif if ((error = get_mod_name(module_name, name)) != 0) return error; pr_debug("initializing module `%s', %d (0x%x) bytes\n", name, codesize, codesize); memcpy_fromfs(&rt, routines, sizeof rt); if ((mp = find_module(name)) == NULL) return -ENOENT; if (codesize & MOD_AUTOCLEAN) { /* * set autoclean marker from codesize... * set usage count to "zero" */ codesize &= ~MOD_AUTOCLEAN; GET_USE_COUNT(mp) = MOD_AUTOCLEAN; } if ((codesize + sizeof (long) + PAGE_SIZE - 1) / PAGE_SIZE > mp->size) return -EINVAL; memcpy_fromfs((char *)mp->addr + sizeof (long), code, codesize); memset((char *)mp->addr + sizeof (long) + codesize, 0, mp->size * PAGE_SIZE - (codesize + sizeof (long))); pr_debug("module init entry = 0x%08lx, cleanup entry = 0x%08lx\n", (unsigned long) rt.init, (unsigned long) rt.cleanup); mp->cleanup = rt.cleanup; /* update kernel symbol table */ if (symtab) { /* symtab == NULL means no new entries to handle */ struct internal_symbol *sym; struct module_ref *ref; int size; int i; int legal_start; if ((error = verify_area(VERIFY_READ, &symtab->size, sizeof(symtab->size)))) return error; size = get_user(&symtab->size); if ((newtab = (struct symbol_table*) kmalloc(size, GFP_KERNEL)) == NULL) { return -ENOMEM; } if ((error = verify_area(VERIFY_READ, symtab, size))) { kfree_s(newtab, size); return error; } memcpy_fromfs((char *)(newtab), symtab, size); /* sanity check */ legal_start = sizeof(struct symbol_table) + newtab->n_symbols * sizeof(struct internal_symbol) + newtab->n_refs * sizeof(struct module_ref); if ((newtab->n_symbols < 0) || (newtab->n_refs < 0) || (legal_start > size)) { printk(KERN_WARNING "Rejecting illegal symbol table (n_symbols=%d,n_refs=%d)\n", newtab->n_symbols, newtab->n_refs); kfree_s(newtab, size); return -EINVAL; } /* relocate name pointers, index referred from start of table */ for (sym = &(newtab->symbol[0]), i = 0; i < newtab->n_symbols; ++sym, ++i) { if ((unsigned long)sym->name < legal_start || size <= (unsigned long)sym->name) { printk(KERN_WARNING "Rejecting illegal symbol table\n"); kfree_s(newtab, size); return -EINVAL; } /* else */ sym->name += (long)newtab; } mp->symtab = newtab; /* Update module references. * On entry, from "insmod", ref->module points to * the referenced module! * Now it will point to the current module instead! * The ref structure becomes the first link in the linked * list of references to the referenced module. * Also, "sym" from above, points to the first ref entry!!! */ for (ref = (struct module_ref *)sym, i = 0; i < newtab->n_refs; ++ref, ++i) { /* Check for valid reference */ struct module *link = module_list; while (link && (ref->module != link)) link = link->next; if (link == (struct module *)0) { printk(KERN_WARNING "Non-module reference! Rejected!\n"); return -EINVAL; } ref->next = ref->module->ref; ref->module->ref = ref; ref->module = mp; } } GET_USE_COUNT(mp) += 1; if ((*rt.init)() != 0) { GET_USE_COUNT(mp) = 0; return -EBUSY; } GET_USE_COUNT(mp) -= 1; mp->state = MOD_RUNNING; return 0; }