Platform Device Drivers-related functions and structures

Source: Internet
Author: User

File Drivers/base/platform. c/*** platform_get_irq-Get an IRQ for a device * @ Dev: platform device * @ num: IRQ Number Index */INT platform_get_irq (struct platform_device * Dev, unsigned int num) {struct resource * r = platform_get_resource (Dev, ioresource_irq, num); return r? R-> Start: 0 ;}

Platform_get_resource (Dev, ioresource_irq, num) obtains the resources matching the num flags and ioresource_irq. The RTC resource structure is as follows, and num corresponds to [2, num 0 corresponds to [1.

File ARCH/ARM/mach-s3c2410/Devs. cstatic struct resource initi_rtc_resource [] = {[0] = {. start = s3c2410_pa_rtc ,. end = s3c2410_pa_rtc + 0xff ,. flags = ioresource_mem,}, [1] = {. start = irq_rtc ,. end = irq_rtc ,. flags = ioresource_irq,}, [2] = {. start = irq_tick ,. end = irq_tick ,. flags = ioresource_irq }};

File Include/Linux/ioport. hresource struct definition: struct resource {const char * Name; unsigned long start, end; unsigned long flags; struct resource * parent, * sibling, * child ;};

File Drivers/base/platform. c/*** platform_get_resource-get a resource for a device * @ Dev: platform device * @ Type: resource type * @ num: resource Index */struct resource * platform_get_resource (struct platform_device * Dev, unsigned int type, unsigned int num) {int I; for (I = 0; I <Dev-> num_resources; I ++) {struct resource * r = & Dev-> resource [I]; If (R-> flags & (ioresource_io | ioresource_mem | ioresource_irq | ioresource_dma )) = type) if (Num -- = 0) return r;} return NULL ;}

File Include/Linux/ioport. h # define request_mem_region (START, N, name) _ request_region (& iomem_resource, (start), (n), (name ))

File kernel/resource. cstruct resource iomem_resource = {. Name = "PCI mem",. Start = 0ul,. End = ~ 0ul,. Flags = ioresource_mem,}; export_symbol (iomem_resource );

The resource in the kernel is a multi-tree with the root of parent (iomem_resource). Each node has several child nodes. The End Node of the child node is smaller than the Start Node of the subsequent node, and is connected by sibling; the start of the child node falls between the start and end of the parent node,

Function _ request_region () is used to find the position of the address space with start as the starting address and N length in the Resource Tree, and create a node res, insert it to the corresponding position in the Resource Tree.

File kernel/resource. c/** this is compatibility stuff for Io resources. ** note how this, unlike the above, knows about * the IO flag meanings (busy etc ). ** request-region creates a new busy region. ** check-region returns non-zero if the area is already busy ** release-region releases a matching busy region. */struct resource * _ request_region (struct resource * parent, unsigned long start, UNS Igned long N, const char * Name) {struct resource * res = kmalloc (sizeof (* res), gfp_kernel); If (RES) {memset (Res, 0, sizeof (* res); res-> name = Name; res-> Start = start; res-> end = start + n-1; res-> flags = ioresource_busy; write_lock (& resource_lock); For (;) {struct resource * Conflict; Conflict = _ request_resource (parent, Res); If (! Conflict) break; If (conflict! = Parent) {parent = conflict; If (! (Conflict-> flags & ioresource_busy) continue;}/* Uhhuh, that didn't work out .. */kfree (RES); Res = NULL; break;} write_unlock (& resource_lock);} return res ;}

File kernel/resource. c
/* Return the conflict entry if you can't request it */static struct resource * __request_resource(struct resource *root, struct resource *new){unsigned long start = new->start;unsigned long end = new->end;struct resource *tmp, **p;if (end < start)return root;if (start < root->start)return root;if (end > root->end)return root;p = &root->child;for (;;) {tmp = *p;if (!tmp || tmp->start > end) {new->sibling = tmp;*p = new;new->parent = root;return NULL;}p = &tmp->sibling;if (tmp->end < start)continue;return tmp;}}

File ARCH/ARM/common/rtctime. CINT register_rtc (struct rtc_ops * OPS) {int ret =-ebusy; down (& rtc_sem); If (rtc_ops = NULL) {rtc_ops = OPS; ret = misc_register (& rtc_miscdev); If (ret = 0) create_proc_read_entry ("Driver/RTC", 0, null, rtc_read_proc, OPS);} Up (& rtc_sem ); return ret ;}

File ARCH/ARM/common/rtctime. cstatic int rtc_read_proc (char * Page, char ** start, off_t off, int count, int * EOF, void * Data) {struct rtc_ops * Ops = data; struct rtc_wkalrm alrm; struct rtc_time TM; char * P = page; If (rtc_read_time (Ops, & TM) = 0) {P + = sprintf (P, "rtc_time \ t: % 02d: % 02d: % 02d \ n "" rtc_date \ t: % 04d-% 02d-% 02d \ n "" rtc_epoch \ t: % 04lu \ n ", TM. tm_hour, TM. tm_min, TM. tm_sec, TM. tm_year + 1900, TM. tm_mon + 1, TM. tm_mday, rtc_epoch);} If (rtc_read_alarm (Ops, & alrm) = 0) {P + = sprintf (P, "alrm_time \ t :"); if (unsigned INT) alrm. time. tm_hour <= 24) P + = sprintf (P, "% 02d:", alrm. time. tm_hour); elsep + = sprintf (P, "**:"); If (unsigned INT) alrm. time. tm_min <= 59) P + = sprintf (P, "% 02d:", alrm. time. tm_min); elsep + = sprintf (P, "**:"); If (unsigned INT) alrm. time. tm_sec <= 59) P + = sprintf (P, "% 02d \ n", alrm. time. Tm_sec); elsep + = sprintf (P, "** \ n"); P + = sprintf (P, "alrm_date \ t:"); If (unsigned INT) alrm. time. tm_year <= 200) P + = sprintf (P, "% 04d-", alrm. time. tm_year + 1900); elsep + = sprintf (P, "*****-"); If (unsigned INT) alrm. time. tm_mon <= 11) P + = sprintf (P, "% 02d-", alrm. time. tm_mon + 1); elsep + = sprintf (P, "**-"); If (unsigned INT) alrm. time. tm_mday <= 31) P + = sprintf (P, "% 02d \ n", alrm. time. tm_mday); elsep + = Sprintf (P, "** \ n"); P + = sprintf (P, "alrm_wakeup \ t: % s \ n", alrm. enabled? "Yes": "no"); P + = sprintf (P, "alrm_pending \ t: % s \ n", alrm. Pending? "Yes": "no");} If (OPS-> proc) P + = OPS-> proc (p); Return p-page ;}

Register a Hybrid device:

File Drivers/Char/Misc. c/*** misc_register-register a miscellaneous device * @ MISC: device structure ** register a miscellaneous device with the kernel. if the minor * number is set to % misc_dynamic_minor a minor number is assigned * and placed in the minor field of the structure. for other cases * the minor number requested is used. ** the structure passed is linked into the kernel and may not be * destroyed until it has been unregistered. ** a zero is returned on success and a negative errno code for * failure. */INT misc_register (struct miscdevice * MISC) {struct miscdevice * C; dev_t dev; int err; down (& misc_sem); list_for_each_entry (C, & misc_list, list) {If (c-> minor = MISC-> minor) {up (& misc_sem); Return-ebusy ;}} if (Misc-> minor = misc_dynamic_minor) {int I = dynamic_minors; while (-- I> = 0) if (misc_minors [I> 3] & (1 <(I & 7) = 0) break; if (I <0) {up (& misc_sem); Return-ebusy;} MISC-> minor = I;} If (Misc-> minor <dynamic_minors) misc_minors [MISC-> minor> 3] | = 1 <(Misc-> minor & 7); If (Misc-> devfs_name [0] = '\ 0 ') {snprintf (Misc-> devfs_name, sizeof (Misc-> devfs_name), "Misc/% s", MISC-> name);} Dev = mkdev (misc_major, misc-> minor); MISC-> class = class_simple_device_add (misc_class, Dev, MISC-> Dev, MISC-> name); If (is_err (Misc-> class )) {err = ptr_err (Misc-> class); goto out;} err = devfs_mk_cdev (Dev, s_ifchr | s_irusr | s_iwusr | s_irgrp, MISC-> devfs_name); If (ERR) {class_simple_device_remove (Dev); goto out;}/** add it to the front, so that later devices can "Override" * earlier defaults */list_add (& MISC-> list, & misc_list); Out: Up (& misc_sem); Return err ;}

Create a proc node and bind the node to the corresponding processing function read_proc.

File Include/Linux/proc_fs.hstatic inline struct proc_dir_entry * create_proc_read_entry (const char * Name, mode_t mode, struct proc_dir_entry * base, read_proc_t * read_proc, void * Data) {struct proc_dir_entry * res = create_proc_entry (name, mode, base); If (RES) {res-> read_proc = read_proc; res-> DATA = data;} return res ;}

File fs/proc/generic. cstruct proc_dir_entry * create_proc_entry (const char * Name, mode_t mode, struct proc_dir_entry * parent) {struct proc_dir_entry * ent; nlink_t nlink; If (s_isdir (mode )) {If (Mode & s_iallugo) = 0) mode | = s_irugo | s_ixugo; nlink = 2 ;}else {If (Mode & s_ifmt) = 0) mode | = s_ifreg; If (Mode & s_iallugo) = 0) mode | = s_irugo; nlink = 1 ;}ent = proc_create (& parent, name, mode, nlink ); if (ENT) {If (s_isdir (mode) {ent-> proc_fops = & proc_dir_operations; ENT-> proc_iops = & proc_dir_inode_operations;} If (proc_register (parent, ENT) <0) {kfree (ENT); ENT = NULL ;}} return ent ;}

File fs/proc/generic. cstatic struct proc_dir_entry * proc_create (struct proc_dir_entry ** parent, const char * Name, mode_t mode, nlink_t nlink) {struct proc_dir_entry * ent = NULL; const char * fn = Name; int Len;/* Make sure name is valid */If (! Name |! Strlen (name) goto out; If (! (* Parent) & xlate_proc_name (name, parent, & FN )! = 0) goto out;/* at this point there must not be any '/'characters beyond * fN */If (strchr (FN,'/') goto out; len = strlen (FN); ENT = kmalloc (sizeof (struct proc_dir_entry) + Len + 1, gfp_kernel); If (! Ent) goto out; memset (ENT, 0, sizeof (struct proc_dir_entry); memcpy (char *) ent) + sizeof (struct proc_dir_entry), FN, len + 1); ENT-> name = (char *) ent) + sizeof (* ent); ENT-> namelen = Len; ENT-> mode = mode; ent-> nlink = nlink; Out: Return ent ;}

File fs/proc/generic. c/** this function parses a name such as "tty/driver/serial", and * returns the struct proc_dir_entry for "/proc/tty/driver ", and * returns "serial" in residual. */static int xlate_proc_name (const char * Name, struct proc_dir_entry ** ret, const char ** residual) {const char * CP = Name, * Next; struct proc_dir_entry * de; intlen; De = & proc_root; while (1) {next = strchr (CP, '/'); If (! Next) break; Len = Next-CP; For (DE = de-> subdir; de; De = de-> next) {If (proc_match (Len, CP, de )) break;} If (! De) Return-enoent; CP + = Len + 1;} * residual = CP; * ret = de; return 0 ;}

File ARCH/ARM/common/rtctime. cvoid Merge (struct rtc_ops * RTC) {down (& rtc_sem); If (RTC = rtc_ops) {remove_proc_entry ("Driver/RTC", null); misc_deregister (& rtc_miscdev ); rtc_ops = NULL;} Up (& rtc_sem );}

File fs/proc/generic. c/** remove a/proc entry and free it if it's not currently in use. * if it is in use, we set the 'deleted' flag. */void remove_proc_entry (const char * Name, struct proc_dir_entry * parent) {struct proc_dir_entry ** P; struct proc_dir_entry * de; const char * fn = Name; int Len; If (! Parent & xlate_proc_name (name, & parent, & FN )! = 0) goto out; Len = strlen (FN); For (P = & parent-> subdir; * P; P = & (* P)-> next) {If (! Proc_match (Len, FN, * p) continue; De = * P; * P = de-> next; de-> next = NULL; if (s_isdir (de-> mode) parent-> nlink --; proc_kill_inodes (de); de-> nlink = 0; warn_on (de-> subdir); If (! Atomic_read (& de-> count) free_proc_entry (de); else {de-> deleted = 1; printk ("remove_proc_entry: % S/% s busy, count = % d \ n ", parent-> name, de-> name, atomic_read (& de-> count) ;} break;} Out: return ;}

drivers/char/misc.c/** *misc_deregister - unregister a miscellaneous device *@misc: device to unregister * *Unregister a miscellaneous device that was previously *successfully registered with misc_register(). Success *is indicated by a zero return, a negative errno code *indicates an error. */int misc_deregister(struct miscdevice * misc){int i = misc->minor;if (list_empty(&misc->list))return -EINVAL;down(&misc_sem);list_del(&misc->list);class_simple_device_remove(MKDEV(MISC_MAJOR, misc->minor));devfs_remove(misc->devfs_name);if (i < DYNAMIC_MINORS && i>0) {misc_minors[i>>3] &= ~(1 << (misc->minor & 7));}up(&misc_sem);return 0;}

kernel/resource.cint release_resource(struct resource *old){int retval;write_lock(&resource_lock);retval = __release_resource(old);write_unlock(&resource_lock);return retval;}

kernel/resource.cstatic int __release_resource(struct resource *old){struct resource *tmp, **p;p = &old->parent->child;for (;;) {tmp = *p;if (!tmp)break;if (tmp == old) {*p = tmp->sibling;old->parent = NULL;return 0;}p = &tmp->sibling;}return -EINVAL;}

arch/sh/kernel/cpu/rtc.c#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)

arch/arm/common/rtctime.cvoid rtc_update(unsigned long num, unsigned long events){spin_lock(&rtc_lock);rtc_irq_data = (rtc_irq_data + (num << 8)) | events;spin_unlock(&rtc_lock);wake_up_interruptible(&rtc_wait);kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.