//------------------------------------------------------------------- // serialno.c (One solution for Midterm II, Question V) // // This module create a pseudo-file that shows the hard disk's // serial-number, along with the name of this module's author. // // programmer: ALLAN CRUSE // written on: 10 MAR 2005 //------------------------------------------------------------------- #include // for init_module() #include // for create_proc_info_entry() #include // for ndelay() #include // for copy_to_user() #include // for inb(), outb() #define IDE_DATA 0x1F0 #define IDE_ERROR 0x1F1 #define IDE_DEVICE 0x1F6 #define IDE_STATUS 0x1F7 #define IDE_COMMAND 0x1F7 #define CMD_IDENTIFY_DEVICE 0xEC char modname[] = "serialno"; // for displaying module's name unsigned short buffer[ 256 ]; // for storing disk information int my_get_info( char *buf, char **start, off_t off, int count ) { int read_device_info( void ), i, error, len = 0; if ( ( error = read_device_info() ) == 0 ) { // show serial-number: 20 ascii characters at word offset 10 char *cp = (char*)&buffer[10]; len += sprintf(buf+len, "Hard disk serial number: "); for (i = 0; i < 20; i++) len += sprintf( buf+len, "%c", cp[i] ); len += sprintf(buf+len, "\n"); } else { // show error-message and the error-code len += sprintf( buf+len, "Error while reading device info. " ); len += sprintf( buf+len, "Error code = 0x%08X\n", error ); } len += sprintf(buf+len, "Module Author: Allan Cruse\n"); return len; } int init_module( void ) { create_proc_info_entry( modname, 0, NULL, my_get_info ); return 0; //SUCCESS } void cleanup_module( void ) { remove_proc_entry( modname, NULL ); } // This helper-function reads device-information from the master disk int read_device_info( void ) { int i, status, timeout, error = 0; // Hard Disk Device-Selection Protocol // wait until BSY==0 (bit 7) and DREQ==0 (bit 3) timeout = 1000; do { status = inb( IDE_STATUS ); if ( (status & 0x88 ) == 0x00 ) break; } while ( --timeout ); if ( timeout == 0 ) return -EBUSY; // select the disk drive outb( 0xE0, IDE_DEVICE ); // master disk, LBA addressing ndelay( 400 ); // delay for 400 nanoseconds status = inb( IDE_STATUS ); if ( (status & 0xC8 ) != 0x40 ) return -EFAULT; // ok, drive is now ready for the command outb( CMD_IDENTIFY_DEVICE, IDE_COMMAND ); ndelay( 400 ); // delay for 400 nanoseconds status = inb( IDE_STATUS ); // was any error info posted? if ( (status & 0x81) == 0x01 ) { error = inb( IDE_ERROR ); return error; } // wait for the DRQ indicator timeout = 1000000; do { status = inb( IDE_STATUS ); if ( (status & 0x88) == 0x08 ) break; } while ( --timeout ); if ( timeout == 0 ) return -EFAULT; // transfer data from the controller's sector-buffer for (i = 0; i < 256; i++) buffer[i] = inw( IDE_DATA ); ndelay( 400 ); // read status register (clears any pending interrupt) status = inb( IDE_STATUS ); return 0; //SUCCESS } MODULE_LICENSE("GPL");