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);}