📄 au1xxx_pm.patch
字号:
+ char data_in[MAX_POWER_CONF_LEN];+ au1xxx_power_dev_t *dev = (au1xxx_power_dev_t *)data;++ DPRINTK("Entering proc_write_timer\n");+ + if (count > MAX_POWER_CONF_LEN)+ len = MAX_POWER_CONF_LEN;+ else+ len = count;++ DPRINTK("Doing copy_from_user with len: %d\n", len);+ if (copy_from_user(data_in, buffer, len))+ return -EFAULT;++ /* read in the value */+ if (au1xxx_pm_setup->feedback_mode == ASCII_FEEDBACK) {+ if (sscanf(data_in, "%lu\n", &timeout_val) != 1) {+ printk(KERN_ERR "Kernel Error: Cannot read new power management settings.\n"); return -EFAULT; }+ } else if (au1xxx_pm_setup->feedback_mode == BINARY_FEEDBACK) {+ DPRINTK("Attempting to write settings via BINARY_FEEDBACK method.\n");+ /* For some reason it doesn't work when you try and do this piece by piece+ * so I've simply created a structure to do it all at once. */+ memcpy(&timeout_val, &data_in, sizeof(unsigned long));+ size = sizeof(unsigned long);+ } else {+ /* reset feedback mode in the error case */+ printk(KERN_WARNING "Invalid power management feedback setting; resetting to default.\n");+ spin_lock_irqsave(&au1xxx_pm_lock, spin_lock_flags);+ au1xxx_pm_setup->feedback_mode = DEFAULT_FEEDBACK;+ spin_unlock_irqrestore(&au1xxx_pm_lock, spin_lock_flags);+ return -EFAULT;+ }++ /* convert the input from seconds into CPU ticks */+ timeout_val = (unsigned long) (timeout_val * HZ);+ + /* actually make the changes */+ spin_lock_irqsave(&au1xxx_pm_lock, spin_lock_flags);+ if ((timeout_val) && (dev->timeout)) {+ dev->timeout = timeout_val;+ mod_timer(&dev->timer, jiffies + dev->timeout);+ } else if ((!timeout_val) && (dev->timeout)) {+ dev->timeout = timeout_val;+ del_timer(&dev->timer);+ } else if ((timeout_val) && (!dev->timeout)) {+ dev->timeout = timeout_val;+ init_timer(&dev->timer);+ dev->timer.function = &au1xxx_pm_service_timer;+ dev->timer.expires = jiffies + dev->timeout;+ dev->timer.data = (unsigned long)dev;+ add_timer(&dev->timer);+ } else if ((!timeout_val) && (!dev->timeout)) {+ /* do nothing in this case, as the timeout is still nothing */+ }+ spin_unlock_irqrestore(&au1xxx_pm_lock, spin_lock_flags);++ return len;+}++static int proc_read_pending(char *page, char **start, off_t off, + int count, int *eof, void *data)+{+ int current_pending = 0;+ int size = 0;+ int i;+ au1xxx_pm_bin_header_t my_bin_hdr;++ /* add up all the pending flags for registered devices */+ for (i = 0; i < MAX_SUPPORTED_DEVICES; i++) {+ if (sys_power_pointers[i]->valid)+ current_pending += sys_power_pointers[i]->state_change_pending;+ }++ if (au1xxx_pm_setup->feedback_mode == ASCII_FEEDBACK) {+ size += sprintf((page + size), "Current pending transactions: %d\n", + current_pending);++ /* handle the buffer */+ if (size <= off + count) + *eof = 1;+ *start = page + off;+ size -= off;+ if (size > count) + size = count;+ if (size < 0) + size = 0;+ } else if (au1xxx_pm_setup->feedback_mode == BINARY_FEEDBACK) {+ my_bin_hdr.report_type = AU1XXX_PM_PENDING;+ my_bin_hdr.num_reports = 1;+ memcpy((page + size), &my_bin_hdr, sizeof(au1xxx_pm_bin_header_t));+ size += sizeof(au1xxx_pm_bin_header_t);+ memcpy((page + size), ¤t_pending, sizeof(int));+ size += sizeof(int);+ } else {+ /* reset feedback mode in the error case */+ printk(KERN_WARNING "Invalid power management feedback setting; resetting to default.\n");+ spin_lock_irqsave(&au1xxx_pm_lock, spin_lock_flags);+ au1xxx_pm_setup->feedback_mode = DEFAULT_FEEDBACK;+ spin_unlock_irqrestore(&au1xxx_pm_lock, spin_lock_flags);+ return -EFAULT;+ } - old_baud_base = get_au1x00_uart_baud_base();- old_cpu_freq = get_au1x00_speed();+ return size;+}++static int proc_read_error(char *page, char **start, off_t off, + int count, int *eof, void *data)+{+ int size = 0;+ int i;+ au1xxx_pm_error_t *error = (au1xxx_pm_error_t *)data;+ au1xxx_pm_bin_header_t my_bin_hdr; - new_cpu_freq = pll * 12 * 1000000;- new_baud_base = (new_cpu_freq / (2 * ((int)(au_readl(SYS_POWERCTRL)&0x03) + 2) * 16));- set_au1x00_speed(new_cpu_freq);- set_au1x00_uart_baud_base(new_baud_base);-- old_refresh = au_readl(MEM_SDREFCFG) & 0x1ffffff;- new_refresh =- ((old_refresh * new_cpu_freq) /- old_cpu_freq) | (au_readl(MEM_SDREFCFG) & ~0x1ffffff);-- au_writel(pll, SYS_CPUPLL);- au_sync_delay(1);- au_writel(new_refresh, MEM_SDREFCFG);- au_sync_delay(1);-- for (i = 0; i < 4; i++) {- if (au_readl- (UART_BASE + UART_MOD_CNTRL +- i * 0x00100000) == 3) {- old_clk =- au_readl(UART_BASE + UART_CLK +- i * 0x00100000);- // baud_rate = baud_base/clk- baud_rate = old_baud_base / old_clk;- /* we won't get an exact baud rate and the error- * could be significant enough that our new- * calculation will result in a clock that will- * give us a baud rate that's too far off from- * what we really want.- */- if (baud_rate > 100000)- baud_rate = 115200;- else if (baud_rate > 50000)- baud_rate = 57600;- else if (baud_rate > 30000)- baud_rate = 38400;- else if (baud_rate > 17000)- baud_rate = 19200;- else- (baud_rate = 9600);- // new_clk = new_baud_base/baud_rate- new_clk = new_baud_base / baud_rate;- au_writel(new_clk,- UART_BASE + UART_CLK +- i * 0x00100000);- au_sync_delay(10);+ if (au1xxx_pm_setup->feedback_mode == ASCII_FEEDBACK) {+ /* print all error information */++ if (!error->dev) {+ size += sprintf((page + size), "There are no errors registered with the power management system.\n");+ }+ else {+ for (i = 0; i < MAX_SUPPORTED_ERRORS; i++) {+ if (sys_error_pointers[i]->dev) {+ size += sprintf((page + size), "-----------------------------\n");+ size += sprintf((page + size), "Device Name: %s\nError Code: %d\nOccurances: %d\nFirst Occurance: %d\nLatest Occurance: %d\n",+ sys_error_pointers[i]->dev->name,+ sys_error_pointers[i]->error_code,+ sys_error_pointers[i]->error_count,+ (int) sys_error_pointers[i]->first_timestamp.tv_sec,+ (int) sys_error_pointers[i]->last_timestamp.tv_sec);+ } } }+ /* handle the buffer */+ if (size <= off + count) + *eof = 1;+ *start = page + off;+ size -= off;+ if (size > count) + size = count;+ if (size < 0) + size = 0;+ } else if (au1xxx_pm_setup->feedback_mode == BINARY_FEEDBACK) {+ /* output all error info in binary format */+ for (i = 0; i < MAX_SUPPORTED_ERRORS; i++) {+ memcpy((page + size), &my_bin_hdr, sizeof(au1xxx_pm_bin_header_t));+ size += sizeof(au1xxx_pm_bin_header_t);+ memcpy((page + size), sys_error_pointers[i], sizeof(au1xxx_pm_error_t));+ size += sizeof(au1xxx_pm_error_t);+ }+ } else {+ /* reset feedback mode in the error case */+ printk(KERN_WARNING "Invalid power management feedback setting; resetting to default.\n");+ spin_lock_irqsave(&au1xxx_pm_lock, spin_lock_flags);+ au1xxx_pm_setup->feedback_mode = DEFAULT_FEEDBACK;+ spin_unlock_irqrestore(&au1xxx_pm_lock, spin_lock_flags);+ return -EFAULT;+ }+ + /* clear all error information */+ spin_lock_irqsave(&au1xxx_pm_lock, spin_lock_flags);+ for (i = 0; i < MAX_SUPPORTED_ERRORS; i++) {+ remove_au1xxx_pm_error(sys_error_pointers[i]); }+ spin_unlock_irqrestore(&au1xxx_pm_lock, spin_lock_flags); + return size;+}+++/***********************************************************************+ * PM DEVICE FUNCTIONS+ ***********************************************************************/+au1xxx_power_dev_t *new_au1xxx_power_device(const char *name, + au1xxx_power_callback cb_func, void *data)+{+ int i;+ au1xxx_power_dev_t *new_dev = NULL;++ DPRINTK("Entering new_au1xxx_power_device()\n");++ spin_lock_irqsave(&au1xxx_pm_lock, spin_lock_flags);++ /* find the first free dev node */+ for (i = 0; i < MAX_SUPPORTED_DEVICES; i++) {+ if (sys_power_pointers[i]->valid == 0) {+ new_dev = sys_power_pointers[i];+ break;+ }+ }++ if (new_dev == NULL) {+ printk(KERN_ERR "Kernel Error: No memory for a new power device.\n");+ return NULL;+ }++ /* initialze the new device node */+ strncpy(new_dev->name, name, MAX_NAME_WIDTH);+ new_dev->callback = *cb_func;+ new_dev->valid = 1;+ new_dev->prev_state = SLEEP_STATE;+ do_gettimeofday(&(new_dev->prev_state_timestamp));+ new_dev->cur_state = AWAKE_STATE;+ do_gettimeofday(&(new_dev->cur_state_timestamp));+ new_dev->data = data;+ new_dev->timeout = 0;+ + /* Create a /proc/pm entry for both read and write if the system has loaded+ * the proc_fs driver. */+ if (system_dev->proc_entry != NULL) {+ DPRINTK("Creating a /proc/pm entry for the new device.\n");+ new_dev->proc_entry = create_proc_entry(name, 0644, power_dir);+ if (new_dev->proc_entry == NULL) + goto no_new_proc_entry;+ new_dev->proc_entry->data = new_dev;+ new_dev->proc_entry->read_proc = proc_read;+ new_dev->proc_entry->write_proc = proc_write;+ } else {+ /* This is not an error condition. It is the case that occurs when a+ * driver loads a power management device before the power management+ * driver itself is loaded. */+ new_dev->proc_entry = NULL;+ }++ /* Create a /proc/pm/timeout entry for both read and write if the system has+ * loaded the proc_fs driver. */++ if (system_dev->timer_proc_entry != NULL) {+ DPRINTK("Creating a /proc/pm/timeout entry for the new device.\n");+ new_dev->timer_proc_entry = create_proc_entry(name, 0644, timeout_dir);+ if (new_dev->timer_proc_entry == NULL) + goto no_new_timer_proc_entry;+ new_dev->timer_proc_entry->data = new_dev;+ new_dev->timer_proc_entry->read_proc = proc_read_timer;+ new_dev->timer_proc_entry->write_proc = proc_write_timer;+ } else {+ /* This is not an error condition. It is the case that occurs when a+ * driver loads a power management device before the power management+ * driver itself is loaded. */+ new_dev->timer_proc_entry = NULL;+ }++ spin_unlock_irqrestore(&au1xxx_pm_lock, spin_lock_flags);+ + DPRINTK("Returning from new_au1xxx_power_device() with a new device.\n");+ return new_dev;++ remove_proc_entry(new_dev->name, timeout_dir);+no_new_timer_proc_entry:+ remove_proc_entry(new_dev->name, power_dir);+no_new_proc_entry:++ printk(KERN_WARNING "Unable to create a /proc entry for a new power management device.\n");+ return NULL;+}++int remove_au1xxx_power_device(au1xxx_power_dev_t *dev) {+ int retval = 0;++ spin_lock_irqsave(&au1xxx_pm_lock, spin_lock_flags);++ if ((system_dev->proc_entry == NULL) || (dev == NULL)) {+ retval = ERROR_INVALID_DEVICE;+ printk(KERN_WARNING "Power management error: accessing invalid device.\n");+ return retval;+ }++ /* clear the device from the array */+ dev->valid = 0;+ strncpy(dev->name, "", strlen(""));+ dev->callback = NULL;+ dev->cur_state = SLEEP_STATE;+ do_gettimeofday(&(dev->cur_state_timestamp));+ dev->prev_state = SLEEP_STATE;+ do_gettimeofday(&(dev->prev_state_timestamp));+ dev->data = NULL;+ dev->timeout = 0;++ /* remove the proc entries if they exist */+ if (dev->proc_entry) + remove_proc_entry(dev->name, power_dir);+ if (dev->timer_proc_entry) + remove_proc_entry(dev->name, timeout_dir);++ spin_unlock_irqrestore(&au1xxx_pm_lock, spin_lock_flags); - /* We don't want _any_ interrupts other than- * match20. Otherwise our calibrate_delay()- * calculation will be off, potentially a lot.- */- intc0_mask = save_local_and_disable(0);- intc1_mask = save_local_and_disable(1);- local_enable_irq(AU1000_TOY_MATCH2_INT);- spin_unlock_irqrestore(&pm_lock, flags);- calibrate_delay();- restore_local_and_enable(0, intc0_mask);- restore_local_and_enable(1, intc1_mask); return retval; } +au1xxx_pm_error_t *new_au1xxx_pm_error(int error_code, au1xxx_power_dev_t *dev) {+ au1xxx_pm_error_t *ret_error_t = NULL;+ int i;++ if (dev == NULL) {+ ret_error_t = NULL;+ printk(KERN_ERR "Invalid Au1xxx power management device access.\n");+ return ret_error_t;+ } -static struct ctl_table pm_table[] = {- {ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, &pm_do_suspend},- {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &pm_do_sleep},- {CTL_ACPI, "freq", NULL, 0, 0600, NULL, &pm_do_freq},- {0}-};+ /* find a matching error structure or a free error struct */+ for (i = 0; i < MAX_SUPPORTED_ERRORS; i++) {+ if (sys_error_pointers[i]->dev == dev)+ break;+ /* each device is allowed one error structure, so if it has an allocated+ * structre, return it */+ else if (sys_error_pointers[i]->dev == NULL)+ break;+ }+ if (i == MAX_SUPPORTED_ERRORS) {+ ret_error_t = NULL;+ printk(KERN_ERR "No available resources for power management error reporting.\n");+ return ret_error_t;+ } -static struct ctl_table pm_dir_table[] = {- {CTL_ACPI, "pm", NULL, 0, 0555, pm_table},- {0}-};+ /* update the error structure */+ if ((sys_error_pointers[i]->dev == dev) &&+ (sys_error_pointers[i]->error_code == error_code)) {+ sys_error_pointers[i]->error_count++;+ do_gettimeofday(&(sys_error_pointers[i]->last_timestamp));+ }+ /* the 'else' case handles new error structure as well as devices+ * experiencing a new error */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -