On Thu, 19 Apr 2007 21:00:55 +0200 Wim Van Sebroeck <[EMAIL PROTECTED]> wrote:
> Hi Andrew, > > > > On Tue, 17 Apr 2007 20:58:49 +0200 Wim Van Sebroeck <[EMAIL PROTECTED]> > > > wrote: > > > Would anyone object if we would merge the "full bells and whistles" > > > drivers for > > > the pcwd isa and pci cards in the kernel tree. (It basically only adds > > > some extra > > > /proc routines). This would make it easier to maintain the "full bells > > > and whistles" > > > driver. > > > > It's hard to answer that question. Please send the patches out in the > > usual manner for review and comment. > > for the pcwd.c driver the patch would be as follows (see below). > I'll create the patch for pcwd_pci.c later this week. > > #include <linux/module.h> /* For module specific items */ > @@ -65,13 +73,18 @@ > #include <linux/fs.h> /* For file operations */ > #include <linux/ioport.h> /* For io-port access */ > #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ > +#include <linux/string.h> /* For string manipulations */ > +#ifdef CONFIG_PROC_FS > +#include <linux/stat.h> /* For S_IFREG/S_IRUGO/S_IWUSR */ > +#include <linux/proc_fs.h> /* For create_proc_entry/remove_proc_entry/ ... > */ > +#endif Please avoid the ifdefs here if at all possible. They increase the chances of the build failing as people change configs. > /* module parameters */ > +#define CELSIUS 0 > +#define FAHRENHEIT 1 > +static int proc_temp_mode = CELSIUS; > +module_param(proc_temp_mode, int, 0); > +MODULE_PARM_DESC(proc_temp_mode, "which temperature mode to use in /proc/ > 0=Celsius, 1=Fahrenheit (default=0)"); hm, is that a good idea? Making the contents of /proc files dependent upon some module parameter? I'd have thought that it would be better to remove this option and either a) offer two /proc files: one for Celcius, one for Fahrenheit b) Put both values into the same /proc file (one per line) c) Just remove the Fahrenheit option altogether - let it join cubits, furlongs, etc. I mean, how is an application to make sense of that information if its units depend upon some module parameter, or a kernel boot option? > + pcwd_private.card_status=ENABLED; Missing a ' ' around the '='. Several instances. > -static int pcwd_get_temperature(int *temperature) > +static int pcwd_get_temperature(int *temperature, int temp_mode) > { > /* check that port 0 gives temperature info and no command results */ > if (pcwd_private.command_mode) > @@ -543,22 +577,358 @@ > if (!pcwd_private.supports_temp) > return -ENODEV; > > + spin_lock(&pcwd_private.io_lock); > + *temperature = inb(pcwd_private.io_addr); > + spin_unlock(&pcwd_private.io_lock); I doubt if the locking here does anything useful. > + > /* > - * Convert celsius to fahrenheit, since this was > + * Convert celsius to fahrenheit, this is normally > * the decided 'standard' for this return value. > */ > - spin_lock(&pcwd_private.io_lock); > - *temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32; > - spin_unlock(&pcwd_private.io_lock); > + if (temp_mode == FAHRENHEIT) > + *temperature = (*temperature * 9 / 5) + 32; > > if (debug >= DEBUG) { > - printk(KERN_DEBUG PFX "temperature is: %d F\n", > - *temperature); > + printk(KERN_DEBUG PFX "temperature is: %d %s\n", > + *temperature, (temp_mode == CELSIUS) ? "C" :"F"); > } > > return 0; > } > > +#ifdef CONFIG_PROC_FS > +static int > +pcwd_reset_pc(void) static int pcwd_reset_pc(void) please. > +static int > +pcwd_set_timeout(char *sub_command) Ditto (whole patchset (perhaps whole subsystem ;))) > +{ > + char *new_sub_command = sub_command; > + int i; > + > + while (*sub_command == ' ') > + sub_command++; > + if (sub_command == new_sub_command) { > + printk(KERN_ERR PFX "illegal timeout argument '%s'\n", > sub_command); > + return 1; > + } > + i = simple_strtoul(sub_command, NULL, 0); darn, we do this sort of gunk in a lot of places. Isn't there some library function somewhere we can use? > + if (!pcwd_set_heartbeat(i)) { > + if (debug >= VERBOSE) > + printk(KERN_INFO PFX "timeout %d\n", heartbeat); > + } else { > + printk(KERN_ERR PFX > + "illegal timeout argument '%s', should be a number > between 2 and 7200\n", 80 columns? > + sub_command); > + return 1; > + } > + return 0; > +} > + > > .. > > +static void > +pcwd_user_help(void) > +{ > + printk(" pcwd proc command interface help:\n"); > + printk(" ping, pong, tickle - tickle the timer\n"); > + printk(" hardreset - reset pc\n"); > + printk(" enable, start - start the watchdog\n"); > + printk(" disable, stop - stop the watchdog\n"); > + printk(" clear - clear trip status and led\n"); > + printk(" verbose, debug, quiet - command reponse\n"); > + printk(" fahrenheit, celsius - display temp in\n"); > + printk(" extended commands:\n"); > + printk(" arm [val] - isa [30,60,90]\n"); > + printk(" timeout [val]\n"); > +} This could all be done with a single printk() statement. It's missing a KERN_FOO facility level. > +static int > +pcwd_user_command(char *user_command) > +{ > + if ((strcmp(user_command, "ping") == 0) > + || (strcmp(user_command, "pong") == 0) > + || (strcmp(user_command, "tickle") == 0)) { > + pcwd_keepalive(); > + if (debug >= VERBOSE) > + printk(KERN_INFO PFX "ping...\n"); > + } else if ((strcmp(user_command, "enable") == 0) > + || (strcmp(user_command, "start") == 0)) { > + if (!pcwd_start()) { > + if (debug >= VERBOSE) > + printk(KERN_INFO PFX "watchdog enabled.\n"); > + } > + } else if ((strcmp(user_command, "disable") == 0) > + || (strcmp(user_command, "stop") == 0)) { > + if (!pcwd_stop()) { > + if (debug >= VERBOSE) > + printk(KERN_INFO PFX "watchdog disabled!\n"); > + } > + } else if (strcmp(user_command, "clear") == 0) { > + pcwd_clear_status(); > + if (debug >= VERBOSE) > + printk(KERN_INFO PFX "cleared trip status\n"); > + } else if (strcmp(user_command, "hardreset") == 0) { > + pcwd_reset_pc(); > + if (debug >= VERBOSE) > + printk(KERN_INFO PFX "hardreset PC!\n"); > + } else if (strcmp(user_command, "quiet") == 0) { > + debug = QUIET; > + } else if (strcmp(user_command, "verbose") == 0) { > + debug = VERBOSE; > + printk(KERN_INFO PFX "verbose mode on.\n"); > + } else if (strcmp(user_command, "debug") == 0) { > + debug = DEBUG; > + printk(KERN_INFO PFX "debug mode on.\n"); > + } else if (strcmp(user_command, "celsius") == 0) { > + proc_temp_mode = CELSIUS; > + if (debug >= VERBOSE) > + printk(KERN_INFO PFX "display temp in Celsius.\n"); > + } else if (strcmp(user_command, "fahrenheit") == 0) { > + proc_temp_mode = FAHRENHEIT; > + if (debug >= VERBOSE) > + printk(KERN_INFO PFX "display temp in Fahrenheit.\n"); > + } else if (strcmp(user_command, "help") == 0) { > + pcwd_user_help(); > + } else if (strncmp(user_command, "arm", 3) == 0) { > + if ((pcwd_private.fw_ver_str[0] >= '1') > + && (pcwd_private.fw_ver_str[2] >= '2')) { > + if (pcwd_set_arm(&user_command[3])) { > + printk(KERN_ERR PFX "arm FAILED.\n"); > + return 0; > + } > + } else { > + printk(KERN_ERR > + "pcwd: ISA Card and firmware > 1.20 needed.\n"); > + return 0; > + } > + } else if (strncmp(user_command, "timeout", 7) == 0) { > + if (pcwd_set_timeout(&user_command[7])) { > + printk(KERN_ERR PFX "timeout FAILED.\n"); > + return 0; > + } > + } else { > + printk(KERN_ERR "illegal user command: '%s'\n", user_command); > + pcwd_user_help(); > + return 0; > + } > + return 1; > +} parse, parse, parse, parse. We really do need stronger libraries for this sort of thing. > +static int > +pcwd_write_proc(struct file *file, const char *buffer, > + unsigned long count, void *data) > +{ > + char command_buffer[80]; > + int rc, length; > + > + /* write only allowed for root users */ > + if (current->euid != 0) > + return -EACCES; Are the permissions on the /proc file not sufficient? Surely it's wrong to be testing for root anyway. capable(CAP_SYS_ADMIN) would be more typical. Or CAP_RAW_IO or something. But not this. > + if (count > sizeof (command_buffer) - 1) > + return -EINVAL; > + > + if (copy_from_user(command_buffer, buffer, count)) > + return -EFAULT; > + > + command_buffer[count] = '\0'; > + length = strlen(command_buffer); > + if (command_buffer[length - 1] == '\n') > + command_buffer[--length] = '\0'; > + > + spin_lock(&pcwd_private.proc_lock); > + rc = pcwd_user_command(command_buffer); > + spin_unlock(&pcwd_private.proc_lock); > + return (rc ? count : -EBUSY); > +} > + > +/* This macro frees the machine specific function from bounds checking and > + * * this like that... [from nvram.c]*/ > +#define PRINT_PROC(fmt,args...) \ > + do { \ > + *len += sprintf( buffer+*len, fmt, ##args ); \ > + if (*begin + *len > offset + size) \ > + return( 0 ); \ > + if (*begin + *len < offset) { \ > + *begin += *len; \ > + *len = 0; \ > + } \ > + } while(0) A `return' hidden in a macro like this is pretty foul. We'd prefer that new instances not be added to the kernel. Can we please find a tasteful way of reimplementing this? Cannot the seq_file interface be used? > +static int > +pcwd_proc_info(unsigned char *buf, char *buffer, int *len, > + off_t * begin, off_t offset, int size) > +{ > + int sw, i; > + > + PRINT_PROC("%s\n", DRIVER_VERSION); > + > + if (pcwd_private.revision == PCWD_REVISION_C) { > + PRINT_PROC("Firmware : Version %s\n", > pcwd_private.fw_ver_str); > + PRINT_PROC("Option Switch: Delay Time "); > + sw = pcwd_get_option_switches(); > + switch (sw & 0x07) { > + case 0: > + PRINT_PROC("20 s"); > + break; > + case 1: > + PRINT_PROC("40 s"); > + break; > + case 2: > + PRINT_PROC("1 min"); > + break; > + case 3: > + PRINT_PROC("5 min"); > + break; > + case 4: > + PRINT_PROC("10 min"); > + break; > + case 5: > + PRINT_PROC("30 min"); > + break; > + case 6: > + PRINT_PROC("1 h"); > + break; > + case 7: > + PRINT_PROC("2 h"); > + break; > + } > + PRINT_PROC((sw & 0x08) ? ", POD on" : ", POD off"); > + PRINT_PROC((sw & 0x10) ? ", TRE on" : ", TRE off"); > + PRINT_PROC((sw & 0x20) ? ", R2M on" : ", R2M off"); > + PRINT_PROC((sw & 0x40) ? ", R1M on" : ", R1M off"); > + PRINT_PROC((sw & 0x80) ? ", RTM on\n" : ", RTM off\n"); > + } else { > + PRINT_PROC("Firmware ROM not present\n"); > + } > + > + PRINT_PROC("Temperature : "); > + if (pcwd_private.supports_temp && (!pcwd_get_temperature(&i, > proc_temp_mode))) { > + PRINT_PROC("%d ", i); > + PRINT_PROC((proc_temp_mode == CELSIUS) ? "__C\n" : "__F\n"); > + } else { > + PRINT_PROC("Card without temp option\n"); > + } > + > + if (pcwd_private.card_status == ENABLED) > + PRINT_PROC("Card status : Timer enabled\n"); > + else > + PRINT_PROC("Card status : Timer disabled\n"); > + > + spin_lock(&pcwd_private.io_lock); > + if (pcwd_private.revision == PCWD_REVISION_A) { > + sw = inb_p(pcwd_private.io_addr) & WD_WDRST; > + } else { > + sw = inb_p(pcwd_private.io_addr + 1) & WD_REVC_WTRP; > + } > + spin_unlock(&pcwd_private.io_lock); > + PRINT_PROC("Reboot status: "); > + PRINT_PROC(sw ? "Tripped\n" : "Not tripped\n"); > + > + if ((pcwd_private.boot_status & WDIOF_CARDRESET) && > (pcwd_private.boot_status & WDIOF_OVERHEAT)) { > + PRINT_PROC("Boot status : CPU Overheat + Watchdog caused > reboot\n"); > + } else if (pcwd_private.boot_status & WDIOF_CARDRESET) { > + PRINT_PROC("Boot status : Watchdog caused reboot\n"); > + } else if (pcwd_private.boot_status & WDIOF_OVERHEAT) { > + PRINT_PROC("Boot status : CPU Overheat\n"); > + } else { > + PRINT_PROC("Boot status : Cold boot or reset\n"); > + } Lots of braces can (shold) be removed in here. > + // PRINT_PROC("Ping Count : %d\n", ping_counter); > + return 1; > +} > + > +static int > +pcwd_read_proc(char *buffer, char **start, off_t offset, > + int size, int *eof, void *data) > +{ > + int len = 0; > + off_t begin = 0; > + > + spin_lock(&pcwd_private.proc_lock); > + *eof = pcwd_proc_info(NULL, buffer, &len, &begin, offset, size); > + spin_unlock(&pcwd_private.proc_lock); > + > + if (offset >= begin + len) > + return (0); > + *start = buffer + (offset - begin); // CORRECTED !!!! > + return (size < begin + len - offset ? size : begin + len - offset); > +} > +#endif /* PROC_FS */ > + > > ... > > +#ifdef CONFIG_PROC_FS > + if ((pcwd_private.proc_pcwd = > + create_proc_entry(WATCHDOG_NAME, S_IFREG | S_IRUGO | S_IWUSR, 0))) > { > + pcwd_private.proc_pcwd->read_proc = pcwd_read_proc; > + pcwd_private.proc_pcwd->write_proc = pcwd_write_proc; > + } > +#endif We prefer a = b(); if (a) over if ((a = b()) - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/