Chinaunix首页 | 论坛 | 博客
  • 博客访问: 107767
  • 博文数量: 41
  • 博客积分: 2520
  • 博客等级: 少校
  • 技术积分: 440
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-22 16:25
文章分类

全部博文(41)

文章存档

2010年(41)

我的朋友

分类: LINUX

2010-01-27 10:31:25

驱动的注册:

 

首先以设备类型来分类,对于每种类型的设备,分为frontback两种情况,分别有不同的设备驱动程序。

前端设备驱动程序将注册到前端总线;后端设备驱动程序将注册到后端总线。

例如,对于块设备,存在struct xenbus_driver blkfrontstruct xenbus_driver blkback两种驱动程序。

 

static const struct xenbus_device_id blkfront_ids[] = {

                   { "vbd" },

                   { "" }

};

MODULE_ALIAS("xen:vbd");

static struct xenbus_driver blkfront = {

                   .name = "vbd",

                   .owner = THIS_MODULE,

                   .ids = blkfront_ids,

                   .probe = blkfront_probe,

                   .remove = blkfront_remove,

                   .resume = blkfront_resume,

                   .otherend_changed = backend_changed,

                   .is_ready = blkfront_is_ready,

};

 

static const struct xenbus_device_id blkback_ids[] = {

                   { "vbd" },

                   { "" }

};

static struct xenbus_driver blkback = {

                   .name = "vbd",

                   .owner = THIS_MODULE,

                   .ids = blkback_ids,

                   .probe = blkback_probe,

                   .remove = blkback_remove,

                   .otherend_changed = frontend_changed

};

 

static int __init xlblk_init(void)

{

                   if (!is_running_on_xen())

                                     return -ENODEV;

 

                   return xenbus_register_frontend(&blkfront);

}

module_init(xlblk_init);


int xenbus_register_frontend(struct xenbus_driver *drv)

{

                   int ret;

 

                   drv->read_otherend_details = read_backend_details;

 

                   ret = xenbus_register_driver_common(drv, &xenbus_frontend);

                   if (ret)

                                     return ret;

 

                   /* If this driver is loaded as a module wait for devices to attach. */

                   wait_for_devices(drv);

 

                   return 0;

}


int xenbus_register_driver_common(struct xenbus_driver *drv,

                                                                             struct xen_bus_type *bus)

struct xen_bus_type结构体(只有xenbus_frontendxenbus_backend两种类型)初始化struct xenbus_driver里面struct device_driver类型结构体driver

{

                   int ret;

 

                   if (bus->error)

                                     return bus->error;

 

                   drv->driver.name = drv->name;

                   drv->driver.bus = &bus->bus;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)

                   drv->driver.owner = drv->owner;

#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)

                   drv->driver.probe = xenbus_dev_probe;

                   drv->driver.remove = xenbus_dev_remove;

                   drv->driver.shutdown = xenbus_dev_shutdown;

#endif

 

                   mutex_lock(&xenwatch_mutex);

              ret = driver_register(&drv->driver);             // 注册device_driver

                   mutex_unlock(&xenwatch_mutex);

                   return ret;

}


/* Bus type for frontend drivers. */

static xen_bus_type xenbus_frontend = {

                   .root = "device",

                   .levels = 2,                                    /* device/type/ */

                   .get_bus_id = frontend_bus_id,

                   .probe = xenbus_probe_frontend,

                   .error = -ENODEV,

                   .bus = {

                                     .name     = "xen",

                                     .match    = xenbus_match,

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)

                                     .probe    = xenbus_dev_probe,

                                     .remove   = xenbus_dev_remove,

                                     .shutdown = xenbus_dev_shutdown,

                                     .uevent   = xenbus_uevent_frontend,

#endif

                   },

                   .dev = {

                                     .bus_id = "xen",

                   },

};

 

static struct xen_bus_type xenbus_backend = {

                   .root = "backend",

                   .levels = 3,                                    /* backend/type// */

                   .get_bus_id = backend_bus_id,

                   .probe = xenbus_probe_backend,

                   .error = -ENODEV,

                   .bus = {

                                     .name     = "xen-backend",

                                     .match    = xenbus_match,

                                     .probe    = xenbus_dev_probe,

                                     .remove   = xenbus_dev_remove,

//                                   .shutdown = xenbus_dev_shutdown,

                                     .uevent   = xenbus_uevent_backend,

                   },

                   .dev = {

                                     .bus_id = "xen-backend",

                   },

}

 

对总线结构体bus_type进行了包装

{

                   char *root;

                   int error;

                   unsigned int levels;

                   int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);

                   int (*probe)(const char *type, const char *dir);

                   struct bus_type bus;

                   struct device dev;

};


Ø         通用设备模型结构体

1.         struct bus_type

2.         struct device_driver

3.         struct device

 

struct bus_type {

描述了一个系统总线

                   const char                                     * name;

 

                   struct subsystem     subsys;

                   struct kset                                    drivers;

                   struct kset                                    devices;

                   struct klist                                   klist_devices;

                   struct klist                                   klist_drivers;

 

                   struct bus_attribute                  * bus_attrs;

                   struct device_attribute              * dev_attrs;

                   struct driver_attribute              * drv_attrs;

 

                   int                                (*match)(struct device * dev, struct device_driver * drv);

                   int                                (*uevent)(struct device *dev, char **envp,

                                                                             int num_envp, char *buffer, int buffer_size);

                   int                                (*probe)(struct device * dev);

                   int                                (*remove)(struct device * dev);

                   void                              (*shutdown)(struct device * dev);

                   int                                (*suspend)(struct device * dev, pm_message_t state);

                   int                                (*resume)(struct device * dev);

}

 

struct device_driver {

描述了一个设备驱动程序

                   const char                                     * name;                       // 驱动程序的名称

                   struct bus_type                           * bus;                           // 该驱动所管理的设备挂载到的总线

 

                   struct completion     unloaded;

                   struct kobject                               kobj;

                   struct klist                                   klist_devices;

                   struct klist_node      knode_bus;

 

                   struct module                              * owner;

 

                   int             (*probe)    (struct device * dev);

                   int             (*remove) (struct device * dev);

                   void           (*shutdown)               (struct device * dev);

                   int             (*suspend)                 (struct device * dev, pm_message_t state);

                   int             (*resume)                   (struct device * dev);

}

 

struct device {

描述了一个设备

                   struct klist                                   klist_children;

                   struct klist_node      knode_parent;                              /* node in sibling list */

                   struct klist_node      knode_driver;

                   struct klist_node      knode_bus;

                   struct device             * parent;

 

                   struct kobject kobj;

                   char           bus_id[BUS_ID_SIZE];              /* position on parent bus */

                   struct device_attribute uevent_attr;

                   struct device_attribute *devt_attr;

 

                   struct semaphore     sem;          /* semaphore to synchronize calls to

                                                                                              * its driver.

                                                                                              */

 

                   struct bus_type         * bus;                           /* type of bus device is on */

                   struct device_driver *driver;     /* which driver has allocated this

                                                                                                device */

                   void                              *driver_data;             /* data private to the driver */

                   void                              *platform_data;       /* Platform specific data, device

                                                                                                core doesn't touch it */

                   void                              *firmware_data; /* Firmware specific data (e.g. ACPI,

                                                                                                BIOS data),reserved for device core*/

                   struct dev_pm_info  power;

 

                   u64                              *dma_mask;              /* dma mask (if dma'able device) */

                   u64                              coherent_dma_mask;/* Like dma_mask, but for

                                                                                                  alloc_coherent mappings as

                                                                                                  not all hardware supports

                                                                                                  64 bit addresses for consistent

                                                                                                  allocations such descriptors. */

 

                   struct list_head        dma_pools;                /* dma pools (if dma'ble) */

 

                   struct dma_coherent_mem       *dma_mem; /* internal for coherent mem

                                                                                                  override */

 

                   /* class_device migration path */

                   struct list_head        node;

                   struct class                                   *class;                         /* optional*/

                   dev_t                                              devt;                            /* dev_t, creates the sysfs "dev" */

 

                   void           (*release)(struct device * dev);

}

 


/* Inter-domain shared memory communications. */

#define XENSTORE_RING_SIZE 1024

typedef uint32_t XENSTORE_RING_IDX;

#define MASK_XENSTORE_IDX(idx) ((idx) & (XENSTORE_RING_SIZE-1))

struct xenstore_domain_interface {

    char req[XENSTORE_RING_SIZE]; /* Requests to xenstore daemon. */

    char rsp[XENSTORE_RING_SIZE]; /* Replies and async watch events. */

    XENSTORE_RING_IDX req_cons, req_prod;

    XENSTORE_RING_IDX rsp_cons, rsp_prod;

};

 


Xenstore的读写

 

struct xenstore_domain_interface就是xenstore的页面。读写请求的buf都为1024Kxenstore消息的头部是struct xsd_sockmsg

 

struct xsd_sockmsg

{

    uint32_t type;  /* XS_??? */

    uint32_t req_id;/* Request identifier, echoed in daemon's response.  */

    uint32_t tx_id; /* Transaction id (0 if not related to a transaction). */

    uint32_t len;   /* Length of data following this. */

 

    /* Generally followed by nul-terminated string(s). */

};

类型type有以下很多种:

enum xsd_sockmsg_type

{

    XS_DEBUG,

    XS_DIRECTORY,

    XS_READ,

    XS_GET_PERMS,

    XS_WATCH,

    XS_UNWATCH,

    XS_TRANSACTION_START,

    XS_TRANSACTION_END,

    XS_INTRODUCE,

    XS_RELEASE,

    XS_GET_DOMAIN_PATH,

    XS_WRITE,

    XS_MKDIR,

    XS_RM,

    XS_SET_PERMS,

    XS_WATCH_EVENT,

    XS_ERROR,

    XS_IS_DOMAIN_INTRODUCED,

    XS_RESUME,

    XS_SET_TARGET

}

 

Ø         :

void *xenbus_read(struct xenbus_transaction t,

                                       const char *dir, const char *node, unsigned int *len)

{

                   char *path;

                   void *ret;

 

                   path = join(dir, node);

                   if (IS_ERR(path))

                                     return (void *)path;

 

                   ret = xs_single(t, XS_READ, path, len);

                   kfree(path);

                   return ret;

}

 

Ø         :

/* Write the value of a single file.

 * Returns -err on failure.

 */

int xenbus_write(struct xenbus_transaction t,

                                      const char *dir, const char *node, const char *string)

{

                   const char *path;

                   struct kvec iovec[2];

                   int ret;

 

                   path = join(dir, node);

                   if (IS_ERR(path))

                                     return PTR_ERR(path);

 

                   iovec[0].iov_base = (void *)path;

                   iovec[0].iov_len = strlen(path) + 1;

                   iovec[1].iov_base = (void *)string;

                   iovec[1].iov_len = strlen(string);

 

                   ret = xs_error(xs_talkv(t, XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));

                   kfree(path);

                   return ret;

}

EXPORT_SYMBOL_GPL(xenbus_write);

 

 

static void *xs_single(struct xenbus_transaction t,

                                            enum xsd_sockmsg_type type,

                                            const char *string,

                                            unsigned int *len)

{

                   struct kvec iovec;

 

                   iovec.iov_base = (void *)string;

                   iovec.iov_len = strlen(string) + 1;

                   return xs_talkv(t, type, &iovec, 1, len);

}

 

/* Send message to xs, get kmalloc'ed reply.  ERR_PTR() on error. */

static void *xs_talkv(struct xenbus_transaction t,

                                           enum xsd_sockmsg_type type,

                                           const struct kvec *iovec,

                                           unsigned int num_vecs,

                                           unsigned int *len)

{

                   struct xsd_sockmsg msg;

                   void *ret = NULL;

                   unsigned int i;

                   int err;

 

                   msg.tx_id = t.id;

                   msg.req_id = 0;

                   msg.type = type;

                   msg.len = 0;

                   for (i = 0; i < num_vecs; i++)

                                     msg.len += iovec[i].iov_len;       // 获得所有消息中数据的长度

 

                   mutex_lock(&xs_state.request_mutex);

 

                   err = xb_write(&msg, sizeof(msg));                              // 写消息的头部

                   if (err) {

                                     mutex_unlock(&xs_state.request_mutex);

                                     return ERR_PTR(err);

                   }

 

                   for (i = 0; i < num_vecs; i++) {

                                     err = xb_write(iovec[i].iov_base, iovec[i].iov_len);;    // 写消息的本体,可能分块

                                     if (err) {

                                                        mutex_unlock(&xs_state.request_mutex);

                                                        return ERR_PTR(err);

                                     }

                   }

 

                   ret = read_reply(&msg.type, len);                                 // 获得返回值

 

                   mutex_unlock(&xs_state.request_mutex);

 

                   if (IS_ERR(ret))

                                     return ret;

 

                   if (msg.type == XS_ERROR) {

                                     err = get_error(ret);

                                     kfree(ret);

                                     return ERR_PTR(-err);

                   }

 

                   if (msg.type != type) {

                                     if (printk_ratelimit())

                                                        printk(KERN_WARNING

                                                               "XENBUS unexpected type [%d], expected [%d]\n",

                                                               msg.type, type);

                                     kfree(ret);

                                     return ERR_PTR(-EINVAL);

                   }

                   return ret;

}

 

int xb_write(const void *data, unsigned len)

{

                   struct xenstore_domain_interface *intf = xen_store_interface;

                   XENSTORE_RING_IDX cons, prod;

                   int rc;

 

                   while (len != 0) {

                                     void *dst;

                                     unsigned int avail;

 

                                     rc = wait_event_interruptible(

                                                        xb_waitq,                 // 挂载到xb-waitq等待队列等待。条件是有请求存在。

                                                        (intf->req_prod - intf->req_cons) !=

                                                        XENSTORE_RING_SIZE);

                                     if (rc < 0)

                                                        return rc;

 

                                     /* Read indexes, then verify. */

                                     cons = intf->req_cons;

                                     prod = intf->req_prod;

                                     if (!check_indexes(cons, prod)) {

                                                        intf->req_cons = intf->req_prod = 0;

                                                        return -EIO;

                                     }

 

                                     dst = get_output_chunk(cons, prod, intf->req, &avail);

                                     if (avail == 0)             // 获得要写入的请求缓冲区的开始位置,以及可以写入的长度。

                                                        continue;

                                     if (avail > len)

                                                        avail = len;

 

                                     /* Must write data /after/ reading the consumer index. */

                                     mb();

 

                                     memcpy(dst, data, avail);

                                     data += avail;

                                     len -= avail;

 

                                     /* Other side must not see new producer until data is there. */

                                     wmb();

                                     intf->req_prod += avail;

 

                                     /* Implies mb(): other side will see the updated producer. */

                                     notify_remote_via_evtchn(xen_store_evtchn);     // 发送事件通知

                   }

 

                   return 0;

}

 

static void *get_output_chunk(XENSTORE_RING_IDX cons,

                                                              XENSTORE_RING_IDX prod,

                                                              char *buf, uint32_t *len)

{

                   *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);

                   if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)

                                     *len = XENSTORE_RING_SIZE - (prod - cons);

                   return buf + MASK_XENSTORE_IDX(prod);

}

 

static inline void notify_remote_via_evtchn(int port)

{

                   struct evtchn_send send = { .port = port };                                     // xen_store_evtchn

                   VOID(HYPERVISOR_event_channel_op(EVTCHNOP_send, &send));

}
阅读(1374) | 评论(0) | 转发(0) |
0

上一篇:Xenbus (1)

下一篇:kernel-2.6 add ldd3 scull

给主人留下些什么吧!~~