⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 psdev.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *              An implementation of a loadable kernel mode driver providing *              multiple kernel/user space bidirectional communications links. * *              Author:         Alan Cox <alan@cymru.net> * *              This program is free software; you can redistribute it and/or *              modify it under the terms of the GNU General Public License *              as published by the Free Software Foundation; either version *              2 of the License, or (at your option) any later version. * *              Adapted to become the Linux 2.0 Coda pseudo device *              Peter  Braam  <braam@maths.ox.ac.uk> *              Michael Callahan <mjc@emmy.smith.edu> * *              Changes for Linux 2.1 *              Copyright (c) 1997 Carnegie-Mellon University * *              Redone again for InterMezzo *              Copyright (c) 1998 Peter J. Braam *              Copyright (c) 2000 Mountain View Data, Inc. *              Copyright (c) 2000 Tacitus Systems, Inc. *              Copyright (c) 2001 Cluster File Systems, Inc. * *		Extended attribute support *		Copyright (c) 2001 Shirish. H. Phatak *		Copyright (c) 2001 Tacit Networks, Inc. */#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/major.h>#include <linux/sched.h>#include <linux/lp.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/fcntl.h>#include <linux/delay.h>#include <linux/skbuff.h>#include <linux/proc_fs.h>#include <linux/vmalloc.h>#include <linux/fs.h>#include <linux/poll.h>#include <linux/init.h>#include <linux/list.h>#include <asm/io.h>#include <asm/segment.h>#include <asm/system.h>#include <asm/poll.h>#include <asm/uaccess.h>#include <linux/intermezzo_fs.h>#include <linux/intermezzo_upcall.h>#include <linux/intermezzo_psdev.h>#include <linux/intermezzo_kml.h>#ifdef PRESTO_DEVELint  presto_print_entry = 1;int  presto_debug = 4095;#elseint  presto_print_entry = 0;int  presto_debug = 0;#endif/* Like inode.c (presto_sym_iops), the initializer is just to prevent   upc_comms from appearing as a COMMON symbol (and therefore   interfering with other modules that use the same variable name. */struct upc_comm upc_comms[MAX_PRESTODEV] = {{0}};/* * Device operations: map file to upcall structure */static inline struct upc_comm *presto_psdev_f2u(struct file *file){        int minor;        if ( MAJOR(file->f_dentry->d_inode->i_rdev) != PRESTO_PSDEV_MAJOR ) {                EXIT;                return NULL;        }        minor = MINOR(file->f_dentry->d_inode->i_rdev);        if ( minor < 0 || minor >= MAX_PRESTODEV ) {                EXIT;                return NULL;        }        return &(upc_comms[minor]);}inline int presto_lento_up(int minor) {        return upc_comms[minor].uc_pid;}static unsigned int presto_psdev_poll(struct file *file, poll_table * wait){        struct upc_comm *upccom;        unsigned int mask = POLLOUT | POLLWRNORM;        /* ENTRY; this will flood you */        if ( ! (upccom = presto_psdev_f2u(file)) ) {                kdev_t dev = file->f_dentry->d_inode->i_rdev;                printk("InterMezzo: %s, bad device %s\n",                       __FUNCTION__, kdevname(dev));        }        poll_wait(file, &(upccom->uc_waitq), wait);        if (!list_empty(&upccom->uc_pending)) {                CDEBUG(D_PSDEV, "Non-empty pending list.\n");                mask |= POLLIN | POLLRDNORM;        }        /* EXIT; will flood you */        return mask;}/* *      Receive a message written by Lento to the psdev */static ssize_t presto_psdev_write(struct file *file, const char *buf,                                  size_t count, loff_t *off){        struct upc_comm *upccom;        struct upc_req *req = NULL;        struct upc_req *tmp;        struct list_head *lh;        struct lento_down_hdr hdr;        int error;        if ( ! (upccom = presto_psdev_f2u(file)) ) {                kdev_t dev = file->f_dentry->d_inode->i_rdev;                printk("InterMezzo: %s, bad device %s\n",                       __FUNCTION__, kdevname(dev));        }        /* Peek at the opcode, uniquefier */        if ( count < sizeof(hdr) ) {              printk("presto_psdev_write: Lento didn't write full hdr.\n");                return -EINVAL;        }        error = copy_from_user(&hdr, buf, sizeof(hdr));        if ( error )                return error;        CDEBUG(D_PSDEV, "(process,opc,uniq)=(%d,%d,%d)\n",               current->pid, hdr.opcode, hdr.unique);        /* Look for the message on the processing queue. */        lh  = &upccom->uc_processing;        while ( (lh = lh->next) != &upccom->uc_processing ) {                tmp = list_entry(lh, struct upc_req , rq_chain);                if (tmp->rq_unique == hdr.unique) {                        req = tmp;                      /* unlink here: keeps search length minimal */                        list_del(&req->rq_chain);                      INIT_LIST_HEAD(&req->rq_chain);                        CDEBUG(D_PSDEV,"Eureka opc %d uniq %d!\n",                               hdr.opcode, hdr.unique);                        break;                }        }        if (!req) {                printk("psdev_write: msg (%d, %d) not found\n",                       hdr.opcode, hdr.unique);                return(-ESRCH);        }        /* move data into response buffer. */        if (req->rq_bufsize < count) {                printk("psdev_write: too much cnt: %d, cnt: %Zd, "                       "opc: %d, uniq: %d.\n",                       req->rq_bufsize, count, hdr.opcode, hdr.unique);                count = req->rq_bufsize; /* don't have more space! */        }        error = copy_from_user(req->rq_data, buf, count);        if ( error )                return error;        /* adjust outsize: good upcalls can be aware of this */        req->rq_rep_size = count;        req->rq_flags |= REQ_WRITE;        wake_up(&req->rq_sleep);        return(count);}/* *      Read a message from the kernel to Lento */static ssize_t presto_psdev_read(struct file * file, char * buf,                                 size_t count, loff_t *off){        struct upc_comm *upccom;        struct upc_req *req;        int result = count;        if ( ! (upccom = presto_psdev_f2u(file)) ) {                kdev_t dev = file->f_dentry->d_inode->i_rdev;                printk("InterMezzo: %s, bad device %s\n",                       __FUNCTION__, kdevname(dev));        }        CDEBUG(D_PSDEV, "count %Zd\n", count);        if (list_empty(&(upccom->uc_pending))) {                CDEBUG(D_UPCALL, "Empty pending list in read, not good\n");                return -EINVAL;        }        req = list_entry((upccom->uc_pending.next), struct upc_req, rq_chain);        list_del(&(req->rq_chain));      if (! (req->rq_flags & REQ_ASYNC) ) {              list_add(&(req->rq_chain), upccom->uc_processing.prev);      }      req->rq_flags |= REQ_READ;        /* Move the input args into userspace */        if (req->rq_bufsize <= count) {                result = req->rq_bufsize;        }        if (count < req->rq_bufsize) {                printk ("psdev_read: buffer too small, read %Zd of %d bytes\n",                        count, req->rq_bufsize);        }        if ( copy_to_user(buf, req->rq_data, result) ) {                return -EFAULT;        }        /* If request was asynchronous don't enqueue, but free */        if (req->rq_flags & REQ_ASYNC) {                CDEBUG(D_PSDEV, "psdev_read: async msg (%d, %d), result %d\n",                       req->rq_opcode, req->rq_unique, result);                PRESTO_FREE(req->rq_data, req->rq_bufsize);                PRESTO_FREE(req, sizeof(*req));                return result;        }        return result;}static int presto_psdev_ioctl(struct inode *inode, struct file *file,                              unsigned int cmd, unsigned long arg){        struct upc_comm *upccom;        /* XXX is this rdev or dev? */        kdev_t dev = inode->i_rdev;        ENTRY;        upccom = presto_psdev_f2u(file);        if ( !upccom) {                printk("InterMezzo: %s, bad device %s\n",                       __FUNCTION__, kdevname(dev));                EXIT;                return -ENODEV;        }        switch(cmd) {        case TCGETS:                return -EINVAL;        case PRESTO_GETMOUNT: {                /* return all the mounts for this device.  */                int minor = 0;                int len, outlen;                struct readmount readmount;                struct readmount *user_readmount = (struct readmount *) arg;                char * tmp;                int error;                error = copy_from_user(&readmount, (void *)arg,                                       sizeof(readmount));                if ( error )  {                        printk("psdev: can't copy %Zd bytes from %p to %p\n",                                sizeof(readmount), (struct readmount *) arg,                                &readmount);                        EXIT;                        return error;                }                len = readmount.io_len;                minor = MINOR(dev);                PRESTO_ALLOC(tmp, char *, len);                if (!tmp) {                        EXIT;                        return -ENOMEM;                }                outlen = presto_sprint_mounts(tmp, len, minor);                CDEBUG(D_PSDEV, "presto_sprint_mounts returns %d bytes\n",                                outlen);                /* as this came out on 1/3/2000, it could NEVER work.                 * So fix it ... RGM                 * I mean, let's let the compiler do a little work ...                 * gcc suggested the extra ()                 */                error = copy_to_user(readmount.io_string, tmp, outlen);                if ( error ) {                        CDEBUG(D_PSDEV, "Copy_to_user string 0x%p failed\n",                               readmount.io_string);                }                if ((!error) && (error = copy_to_user(&(user_readmount->io_len),                                                      &outlen, sizeof(int))) ) {                        CDEBUG(D_PSDEV, "Copy_to_user len @0x%p failed\n",                               &(user_readmount->io_len));                }                PRESTO_FREE(tmp, len);                EXIT;                return error;        }        case PRESTO_SETPID: {                /*                 * This ioctl is performed by each Lento that starts up                 * and wants to do further communication with presto.                 */                CDEBUG(D_PSDEV, "Setting current pid to %d\n", current->pid);                upccom->uc_pid = current->pid;                if ( !list_empty(&upccom->uc_processing) ) {                        struct list_head *lh;                        struct upc_req *req;                        printk("WARNING: setpid & processing not empty!\n");                        lh = &upccom->uc_processing;                        while ( (lh = lh->next) != &upccom->uc_processing) {                                req = list_entry(lh, struct upc_req, rq_chain);                                /* freeing of req and data is done by the sleeper */                                wake_up(&req->rq_sleep);                        }                }                if ( !list_empty(&upccom->uc_processing) ) {                        printk("BAD: FAILDED TO CLEAN PROCESSING LIST!\n");                }                EXIT;                return 0;        }        case PRESTO_CLEAR_FSETROOT: {                /*                 * Close KML files.                 */                int error;                int saved_pid = upccom->uc_pid;                char *path;                struct {                        char *path;                        int   path_len;                } input;                error = copy_from_user(&input, (char *)arg, sizeof(input));                if ( error ) {                        EXIT;                        return error;                }                PRESTO_ALLOC(path, char *, input.path_len + 1);                if ( !path ) {                        EXIT;                        return -ENOMEM;                }                error = copy_from_user(path, input.path, input.path_len);                if ( error ) {                        PRESTO_FREE(path, input.path_len + 1);                        EXIT;                        return error;                }                path[input.path_len] = '\0';                CDEBUG(D_PSDEV, "clear_fsetroot: path %s\n", path);                upccom->uc_pid = current->pid;                error = presto_clear_fsetroot(path);                upccom->uc_pid = saved_pid;                PRESTO_FREE(path, input.path_len + 1);                EXIT;                return error;        }        case PRESTO_CLEAR_ALL_FSETROOTS: {                /*                 * Close KML files.                 */                int error;                int saved_pid = upccom->uc_pid;                char *path;                struct {                        char *path;                        int   path_len;                } input;                error = copy_from_user(&input, (char *)arg, sizeof(input));                if ( error ) {                        EXIT;                        return error;                }                PRESTO_ALLOC(path, char *, input.path_len + 1);                if ( !path ) {                        EXIT;                        return -ENOMEM;                }                error = copy_from_user(path, input.path, input.path_len);                if ( error ) {                        PRESTO_FREE(path, input.path_len + 1);                        EXIT;                        return error;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -