12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * This comment was taken from the original sony-laptop code
- *
- * ACPI Sony Notebook Control Driver (SNC and SPIC)
- *
- * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
- * Copyright (C) 2007-2009 Mattia Dongili <malattia@linux.it>
- *
- * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
- * which are copyrighted by their respective authors.
- *
- * The SNY6001 driver part is based on the sonypi driver which includes
- * material from:
- *
- * Copyright (C) 2001-2005 Stelian Pop <stelian@popies.net>
- *
- * Copyright (C) 2005 Narayanan R S <nars@kadamba.org>
- *
- * Copyright (C) 2001-2002 Alcôve <www.alcove.com>
- *
- * Copyright (C) 2001 Michael Ashley <m.ashley@unsw.edu.au>
- *
- * Copyright (C) 2001 Junichi Morita <jun1m@mars.dti.ne.jp>
- *
- * Copyright (C) 2000 Takaya Kinjo <t-kinjo@tc4.so-net.ne.jp>
- *
- * Copyright (C) 2000 Andrew Tridgell <tridge@valinux.com>
- *
- * Earlier work by Werner Almesberger, Paul `Rusty' Russell and Paul Mackerras.
- */
- #include <linux/acpi.h>
- #include <linux/pci.h>
- #include <linux/platform_device.h>
- #include <linux/delay.h>
- #include <linux/dmi.h>
- #include <linux/input.h>
- #include "sony-pic.h"
- /***********************************************************
- * *
- * This module based on sony-laptop from kernel sources *
- * Sony Programmable IO Control - SPIC (SNY6001) *
- * *
- ***********************************************************/
- int sonypi_compat_init( void );
- void sonypi_compat_exit(void);
- void sonypi_compat_report_event( u8 event );
- int compat;// = 0
- module_param(compat, int, 0444);
- MODULE_PARM_DESC( compat, "set this if you want to enable backward compatibility mode" );
- static int camera; /* = 0 */
- module_param(camera, int, 0444);
- MODULE_PARM_DESC(camera,
- "set this to 1 to enable Motion Eye camera controls "
- "(only use it if you have a C1VE or C1VN model)");
- /********************
- * INPUT DEVICE *
- ********************/
- static void vgnux_input_sendkey( int key ){
- if( key ){
- input_report_key( vgnux_input_device, key, 1 );
- input_sync( vgnux_input_device );
-
- input_report_key( vgnux_input_device, key, 0 );
- input_sync( vgnux_input_device );
- }
- }
- static int vgnux_register_input( void ){
-
- int err = 0;
- int i;
-
- vgnux_input_device = input_allocate_device();
- if( !vgnux_input_device )return -ENOMEM;
-
- vgnux_input_device->name = KBUILD_MODNAME;
- vgnux_input_device->id.bustype = BUS_ISA;
- vgnux_input_device->id.vendor = PCI_VENDOR_ID_SONY;
-
- vgnux_input_device->keycodesize = sizeof( vgnux_input_keycode_map[0] );
- vgnux_input_device->keycodemax = ARRAY_SIZE( vgnux_input_keycode_map );
- vgnux_input_device->keycode = &vgnux_input_keycode_map;
-
- for( i = 0; vgnux_input_keycode_map[i] != KEY_RESERVED; i++ ){
- input_set_capability( vgnux_input_device, EV_KEY, vgnux_input_keycode_map[i] );
- }
-
- err = input_register_device( vgnux_input_device );
- if( err ) input_free_device( vgnux_input_device );
-
- return err;
- }
- static void vgnux_unregister_input( void ){
- input_unregister_device( vgnux_input_device );
- }
- /************************
- * Platform Device *
- ************************/
- static int sony_pf_add( void ){
- int ret = 0;
-
- ret = platform_driver_register( &sony_pf_driver );
- if (ret) goto out;
- sony_pf_device = platform_device_alloc( KBUILD_MODNAME, -1 );
- if (!sony_pf_device) {
- ret = -ENOMEM;
- goto out_platform_registered;
- }
- ret = platform_device_add(sony_pf_device);
- if (ret) goto out_platform_alloced;
- return 0;
- out_platform_alloced:
- platform_device_put(sony_pf_device);
- sony_pf_device = NULL;
- out_platform_registered:
- platform_driver_unregister(&sony_pf_driver);
- out:
- return ret;
- }
- static void sony_pf_remove(void){
- platform_device_unregister(sony_pf_device);
- platform_driver_unregister(&sony_pf_driver);
- }
- /*****************************
- * low level spic calls *
- ******************************/
- #define ITERATIONS_LONG 10000
- #define ITERATIONS_SHORT 10
- #define wait_on_command(command, iterations) { \
- unsigned int n = iterations; \
- while( --n && (command) )udelay(1); \
- if (!n) printk( KERN_WARNING "[%s] command failed at %s : %s (line %d)\n", \
- KBUILD_MODNAME, __FILE__, __func__, __LINE__); \
- }
- u8 sony_pic_call1(u8 dev){
- u8 v1, v2;
- wait_on_command( inb_p( spic_dev.cur_ioport->io1.minimum + 4 ) & 2, ITERATIONS_LONG );
- outb( dev, spic_dev.cur_ioport->io1.minimum + 4 );
- v1 = inb_p( spic_dev.cur_ioport->io1.minimum + 4 );
- v2 = inb_p( spic_dev.cur_ioport->io1.minimum );
- //printk( KERN_NOTICE "[%s] %s(0x%.2x): 0x%.4x\n", KBUILD_MODNAME, __FUNCTION__, dev, (v2 << 8) | v1 );
- return v2;
- }
- u8 sony_pic_call2(u8 dev, u8 fn){
- u8 v1;
- wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG );
- outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
- wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG );
- outb(fn, spic_dev.cur_ioport->io1.minimum);
- v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
- //printk( KERN_NOTICE "[%s] %s(0x%.2x - 0x%.2x): 0x%.4x\n", KBUILD_MODNAME, __FUNCTION__, dev, fn, v1 );
- return v1;
- }
- static u8 sony_pic_call3(u8 dev, u8 fn, u8 v){
- u8 v1;
- wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
- outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
- wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
- outb(fn, spic_dev.cur_ioport->io1.minimum);
- wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
- outb(v, spic_dev.cur_ioport->io1.minimum);
- v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
- //printk( KERN_NOTICE "[%s] %s(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n", KBUILD_MODNAME, __FUNCTION__, dev, fn, v, v1 );
- return v1;
- }
- /*******************
- * CAMERA *
- *******************/
- //only for export
- static int __sony_pic_camera_ready(void){
- u8 v;
- v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS);
- return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY));
- }
- static int __sony_pic_camera_off(void){
- if (!camera) {
- pr_warn("camera control not enabled\n");
- return -ENODEV;
- }
- wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
- SONYPI_CAMERA_MUTE_MASK),
- ITERATIONS_SHORT);
- if (spic_dev.camera_power) {
- sony_pic_call2(0x91, 0);
- spic_dev.camera_power = 0;
- }
- return 0;
- }
- static int __sony_pic_camera_on(void){
- int i, j, x;
- if (!camera) {
- pr_warn("camera control not enabled\n");
- return -ENODEV;
- }
- if (spic_dev.camera_power)return 0;
- for (j = 5; j > 0; j--) {
- for (x = 0; x < 100 && sony_pic_call2(0x91, 0x1); x++)
- msleep(10);
- sony_pic_call1(0x93);
- for (i = 400; i > 0; i--) {
- if( __sony_pic_camera_ready() ) break;
- msleep(10);
- }
- if( i ) break;
- }
- if (j == 0) {
- pr_warn("failed to power on camera\n");
- return -ENODEV;
- }
- wait_on_command( sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL, 0x5a), ITERATIONS_SHORT );
- spic_dev.camera_power = 1;
- return 0;
- }
- /* External camera command (exported to the motion eye v4l driver) */
- int sony_pic_camera_command(int command, u8 value){
- if (!camera) return -EIO;
- mutex_lock(&spic_dev.lock);
- switch (command) {
- case SONY_PIC_COMMAND_SETCAMERA:
- if( value ) __sony_pic_camera_on();
- else __sony_pic_camera_off();
- break;
- case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
- wait_on_command( sony_pic_call3( 0x90, SONYPI_CAMERA_BRIGHTNESS, value ), ITERATIONS_SHORT );
- break;
- case SONY_PIC_COMMAND_SETCAMERACONTRAST:
- wait_on_command( sony_pic_call3( 0x90, SONYPI_CAMERA_CONTRAST, value ), ITERATIONS_SHORT );
- break;
- case SONY_PIC_COMMAND_SETCAMERAHUE:
- wait_on_command( sony_pic_call3( 0x90, SONYPI_CAMERA_HUE, value ), ITERATIONS_SHORT );
- break;
- case SONY_PIC_COMMAND_SETCAMERACOLOR:
- wait_on_command( sony_pic_call3( 0x90, SONYPI_CAMERA_COLOR, value ), ITERATIONS_SHORT );
- break;
- case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
- wait_on_command( sony_pic_call3( 0x90, SONYPI_CAMERA_SHARPNESS, value ), ITERATIONS_SHORT );
- break;
- case SONY_PIC_COMMAND_SETCAMERAPICTURE:
- wait_on_command( sony_pic_call3( 0x90, SONYPI_CAMERA_PICTURE, value ), ITERATIONS_SHORT );
- break;
- case SONY_PIC_COMMAND_SETCAMERAAGC:
- wait_on_command( sony_pic_call3( 0x90, SONYPI_CAMERA_AGC, value ), ITERATIONS_SHORT );
- break;
- default:
- pr_err("sony_pic_camera_command invalid: %d\n", command);
- break;
- }
- mutex_unlock(&spic_dev.lock);
- return 0;
- }
- EXPORT_SYMBOL(sony_pic_camera_command);
- /***************************************************************
- * gprs/edge modem (SZ460N and SZ210P), thanks to Joshua Wise *
- ***************************************************************/
- static void __sony_pic_set_wwanpower( u8 state ){
- state = !!state;
- if ( spic_dev.wwan_power == state ) return;
- sony_pic_call2( 0xB0, state );
- sony_pic_call1( 0x82 );
- spic_dev.wwan_power = state;
- }
- static ssize_t sony_pic_wwanpower_store( struct device *dev, struct device_attribute *attr, const char *buffer, size_t count ){
- unsigned long value;
- if (count > 31) return -EINVAL;
- if (kstrtoul(buffer, 10, &value)) return -EINVAL;
-
- mutex_lock(&spic_dev.lock);
- __sony_pic_set_wwanpower(value);
- mutex_unlock(&spic_dev.lock);
- return count;
- }
- static ssize_t sony_pic_wwanpower_show(struct device *dev, struct device_attribute *attr, char *buffer){
- ssize_t count;
- mutex_lock(&spic_dev.lock);
- count = sysfs_emit( buffer, "%d\n", spic_dev.wwan_power );
- mutex_unlock(&spic_dev.lock);
- return count;
- }
- /************************************
- * bluetooth subsystem power state *
- ************************************/
- static void __sony_pic_set_bluetoothpower(u8 state){
- state = !!state;
- if (spic_dev.bluetooth_power == state) return;
- sony_pic_call2(0x96, state);
- sony_pic_call1(0x82);
- spic_dev.bluetooth_power = state;
- }
- static ssize_t sony_pic_bluetoothpower_store( struct device *dev, struct device_attribute *attr, const char *buffer, size_t count ){
- unsigned long value;
- if (count > 31) return -EINVAL;
- if (kstrtoul(buffer, 10, &value)) return -EINVAL;
- mutex_lock(&spic_dev.lock);
- __sony_pic_set_bluetoothpower(value);
- mutex_unlock(&spic_dev.lock);
- return count;
- }
- static ssize_t sony_pic_bluetoothpower_show(struct device *dev, struct device_attribute *attr, char *buffer){
- ssize_t count = 0;
- mutex_lock(&spic_dev.lock);
- count = sysfs_emit( buffer, "%d\n", spic_dev.bluetooth_power );
- mutex_unlock(&spic_dev.lock);
- return count;
- }
- /***********************************************************
- * FAN0 information (reverse engineered from ACPI tables) *
- ***********************************************************/
- #define SONY_PIC_FAN0_STATUS 0x93
- static int sony_pic_set_fanspeed(unsigned long value){
- return ec_write(SONY_PIC_FAN0_STATUS, value);
- }
- static int sony_pic_get_fanspeed(u8 *value){
- return ec_read(SONY_PIC_FAN0_STATUS, value);
- }
- static ssize_t sony_pic_fanspeed_store( struct device *dev, struct device_attribute *attr, const char *buffer, size_t count ){
- unsigned long value;
- if (count > 31)return -EINVAL;
- if (kstrtoul(buffer, 10, &value))return -EINVAL;
- if (sony_pic_set_fanspeed(value))return -EIO;
- return count;
- }
- static ssize_t sony_pic_fanspeed_show( struct device *dev, struct device_attribute *attr, char *buffer ){
- u8 value = 0;
- if (sony_pic_get_fanspeed(&value)) return -EIO;
- return sysfs_emit( buffer, "%d\n", value );
- }
- /************
- * ATTRS *
- ************/
- #define SPIC_ATTR(_name, _mode) \
- struct device_attribute spic_attr_##_name = __ATTR(_name, \
- _mode, sony_pic_## _name ##_show, \
- sony_pic_## _name ##_store)
- static SPIC_ATTR(bluetoothpower, 0644);
- static SPIC_ATTR(wwanpower, 0644);
- static SPIC_ATTR(fanspeed, 0644);
- static struct attribute *spic_attributes[] = {
- &spic_attr_bluetoothpower.attr,
- &spic_attr_wwanpower.attr,
- &spic_attr_fanspeed.attr,
- NULL
- };
- static const struct attribute_group spic_attribute_group = {
- .attrs = spic_attributes
- };
- /***********************************
- * ISR: some event is available *
- ***********************************/
- irqreturn_t sony_pic_irq_handler( int irq, void *dev_id ){
- int i, j;
- u8 ev = 0;
- u8 data_mask = 0;
-
- struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
-
- ev = inb_p( dev->cur_ioport->io1.minimum );
- if( dev->cur_ioport->io2.minimum ) data_mask = inb_p( dev->cur_ioport->io2.minimum );
- else data_mask = inb_p( dev->cur_ioport->io1.minimum + dev->evport_offset );
-
-
- /*
- printk( KERN_NOTICE "[%s] event [%.2x] mask [%.2x] port 0x%.4x(+0x%.2x)\n",
- KBUILD_MODNAME,
- ev,
- data_mask,
- dev->cur_ioport->io1.minimum,
- dev->evport_offset
- );
- */
-
-
- if (ev == 0x00 || ev == 0xff) return IRQ_HANDLED;
-
-
- for (i = 0; dev->event_types[i].data; i++) {
- if( data_mask != dev->event_types[i].data ) continue;
- for( j = 0; dev->event_types[i].events[j].data; j++ ) {
- if( ev == dev->event_types[i].events[j].data ) {
- vgnux_input_sendkey( dev->event_types[i].events[j].key );
-
- //events were thrown out as unnecessary
- //sonypi_compat_report_event( dev->event_types[i].events[j].event );
-
- return IRQ_HANDLED;
- }
- }
- }
-
-
- //Still not able to decode the event try to pass it over to the minidriver
- if( dev->handle_irq && dev->handle_irq(data_mask, ev) == 0 ) return IRQ_HANDLED;
-
- printk( KERN_WARNING "[%s] unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
- KBUILD_MODNAME,
- ev,
- data_mask,
- dev->cur_ioport->io1.minimum,
- dev->evport_offset
- );
- return IRQ_HANDLED;
- }
- static int type3_handle_irq( const u8 data_mask, const u8 ev ){
- /*
- * 0x31 could mean we have to take some extra action and wait for
- * the next irq for some Type3 models, it will generate a new
- * irq and we can read new data from the device:
- * - 0x5c and 0x5f requires 0xA0
- * - 0x61 requires 0xB3
- */
- if( data_mask == 0x31 ){
- if ( ev == 0x5c || ev == 0x5f ) sony_pic_call1( 0xA0 );
- else if( ev == 0x61 ) sony_pic_call1( 0xB3 );
- return 0;
- }
- return 1;
- }
- /***********************
- * ACPI RESOURCES *
- ***********************/
- static acpi_status sony_pic_read_possible_resource( struct acpi_resource *resource, void *context ){
- u32 i;
- struct sony_pic_dev *dev = (struct sony_pic_dev *)context;
- switch (resource->type) {
- case ACPI_RESOURCE_TYPE_START_DEPENDENT:
- {
- /* start IO enumeration */
- struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
- if (!ioport)
- return AE_ERROR;
- list_add(&ioport->list, &dev->ioports);
- return AE_OK;
- }
- case ACPI_RESOURCE_TYPE_END_DEPENDENT:
- /* end IO enumeration */
- return AE_OK;
- case ACPI_RESOURCE_TYPE_IRQ:
- {
- struct acpi_resource_irq *p = &resource->data.irq;
- struct sony_pic_irq *interrupt = NULL;
- if (!p || !p->interrupt_count) {
- /*
- * IRQ descriptors may have no IRQ# bits set,
- * particularly those those w/ _STA disabled
- */
- printk( KERN_NOTICE "[%s] Blank IRQ resource\n", KBUILD_MODNAME );
- return AE_OK;
- }
- for (i = 0; i < p->interrupt_count; i++) {
- if (!p->interrupts[i]) {
- pr_warn( "Invalid IRQ %d\n", p->interrupts[i] );
- continue;
- }
- interrupt = kzalloc(sizeof(*interrupt), GFP_KERNEL );
- if( !interrupt ) return AE_ERROR;
- list_add(&interrupt->list, &dev->interrupts);
- interrupt->irq.triggering = p->triggering;
- interrupt->irq.polarity = p->polarity;
- interrupt->irq.shareable = p->shareable;
- interrupt->irq.interrupt_count = 1;
- interrupt->irq.interrupts[0] = p->interrupts[i];
- }
- return AE_OK;
- }
- case ACPI_RESOURCE_TYPE_IO:
- {
- struct acpi_resource_io *io = &resource->data.io;
- struct sony_pic_ioport *ioport =
- list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
- if (!io) {
- printk( KERN_NOTICE "[%s] Blank IO resource\n", KBUILD_MODNAME );
- return AE_OK;
- }
- if (!ioport->io1.minimum) {
- memcpy(&ioport->io1, io, sizeof(*io));
- printk( KERN_NOTICE "[%s] IO1 at 0x%.4x (0x%.2x)\n", KBUILD_MODNAME, ioport->io1.minimum, ioport->io1.address_length );
- }
- else if (!ioport->io2.minimum) {
- memcpy(&ioport->io2, io, sizeof(*io));
- printk( KERN_NOTICE "[%s] IO2 at 0x%.4x (0x%.2x)\n", KBUILD_MODNAME, ioport->io2.minimum, ioport->io2.address_length );
- }
- else {
- pr_err( "Unknown SPIC Type, more than 2 IO Ports\n" );
- return AE_ERROR;
- }
- return AE_OK;
- }
- case ACPI_RESOURCE_TYPE_END_TAG:
- return AE_OK;
- default:
- printk( KERN_NOTICE "[%s] Resource %d isn't an IRQ nor an IO port\n", KBUILD_MODNAME, resource->type );
- return AE_CTRL_TERMINATE;
- }
- }
- static int sony_pic_possible_resources( struct acpi_device *device ){
- int result = 0;
- acpi_status status = AE_OK;
- if (!device) return -EINVAL;
- /* get device status */
- /* see acpi_pci_link_get_current acpi_pci_link_get_possible */
- printk( KERN_NOTICE "[%s] Evaluating _STA\n", KBUILD_MODNAME );
- result = acpi_bus_get_status(device);
- if( result ){
- pr_warn("Unable to read status\n");
- goto end;
- }
- if( !device->status.enabled ) printk( KERN_NOTICE "[%s] Device disabled\n", KBUILD_MODNAME );
- else printk( KERN_NOTICE "[%s] Device enabled\n", KBUILD_MODNAME );
- //Query and parse 'method'
- printk( KERN_NOTICE "[%s] Evaluating %s\n", KBUILD_MODNAME, METHOD_NAME__PRS );
- status = acpi_walk_resources( device->handle, METHOD_NAME__PRS, sony_pic_read_possible_resource, &spic_dev );
- if( ACPI_FAILURE(status) ){
- pr_warn( "Failure evaluating %s\n", METHOD_NAME__PRS );
- result = -ENODEV;
- }
- end:
- return result;
- }
- /***************************
- * DETECT DEVICE TYPE *
- ***************************/
- static void sony_pic_detect_device_type( struct sony_pic_dev *dev ){
-
- struct pci_dev *pcidev;
-
- pcidev = pci_get_device( PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL );
- if( pcidev ){
- dev->model = SONYPI_DEVICE_TYPE1;
- dev->evport_offset = SONYPI_TYPE1_OFFSET;
- dev->event_types = dummy_events;
- goto out;
- }
-
- pcidev = pci_get_device( PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, NULL );
- if( pcidev ){
- dev->model = SONYPI_DEVICE_TYPE2;
- dev->evport_offset = SONYPI_TYPE2_OFFSET;
- dev->event_types = dummy_events;
- goto out;
- }
-
- pcidev = pci_get_device( PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, NULL );//VGN-UX
- if( pcidev ){
- dev->model = SONYPI_DEVICE_TYPE3;
- dev->handle_irq = type3_handle_irq;
- dev->evport_offset = SONYPI_TYPE3_OFFSET;
- //dev->event_types = type3_events;
- dev->event_types = vgnux_events;
- goto out;
- }
- pcidev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, NULL );
- if( pcidev ){
- dev->model = SONYPI_DEVICE_TYPE3;
- dev->handle_irq = type3_handle_irq;
- dev->evport_offset = SONYPI_TYPE3_OFFSET;
- dev->event_types = dummy_events;
- goto out;
- }
-
- pcidev = pci_get_device( PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_1, NULL );
- if( pcidev ){
- dev->model = SONYPI_DEVICE_TYPE3;
- dev->handle_irq = type3_handle_irq;
- dev->evport_offset = SONYPI_TYPE3_OFFSET;
- dev->event_types = dummy_events;
- goto out;
- }
-
- /* default */
- dev->model = SONYPI_DEVICE_TYPE2;
- dev->evport_offset = SONYPI_TYPE2_OFFSET;
- dev->event_types = dummy_events;
-
- out:
- pci_dev_put(pcidev);
-
- pr_info("[%s]detected Type%d model\n",
- KBUILD_MODNAME,
- dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
- dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3 );
- }
- /*************************
- * SPIC DEVICE INIT *
- *************************/
- //Based on drivers/acpi/pci_link.c:acpi_pci_link_set
- //Call _SRS to set current resources
- static int sony_pic_enable( struct acpi_device *device, struct sony_pic_ioport *ioport, struct sony_pic_irq *irq ){
- acpi_status status;
- int result = 0;
- /* Type 1 resource layout is:
- * IO
- * IO
- * IRQNoFlags
- * End
- *
- * Type 2 and 3 resource layout is:
- * IO
- * IRQNoFlags
- * End
- */
- struct {
- struct acpi_resource res1;
- struct acpi_resource res2;
- struct acpi_resource res3;
- struct acpi_resource res4;
- } *resource;
- struct acpi_buffer buffer = { 0, NULL };
- if (!ioport || !irq) return -EINVAL;
- /* init acpi_buffer */
- resource = kzalloc(sizeof(*resource) + 1, GFP_KERNEL);
- if (!resource) return -ENOMEM;
- buffer.length = sizeof(*resource) + 1;
- buffer.pointer = resource;
- /* setup Type 1 resources */
- if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
- /* setup io resources */
- resource->res1.type = ACPI_RESOURCE_TYPE_IO;
- resource->res1.length = sizeof(struct acpi_resource);
- memcpy(&resource->res1.data.io, &ioport->io1, sizeof(struct acpi_resource_io));
- resource->res2.type = ACPI_RESOURCE_TYPE_IO;
- resource->res2.length = sizeof(struct acpi_resource);
- memcpy(&resource->res2.data.io, &ioport->io2, sizeof(struct acpi_resource_io));
- /* setup irq resource */
- resource->res3.type = ACPI_RESOURCE_TYPE_IRQ;
- resource->res3.length = sizeof(struct acpi_resource);
- memcpy(&resource->res3.data.irq, &irq->irq, sizeof(struct acpi_resource_irq));
- /* we requested a shared irq */
- resource->res3.data.irq.shareable = ACPI_SHARED;
- resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG;
- resource->res4.length = sizeof(struct acpi_resource);
- }
- /* setup Type 2/3 resources */
- else {
- /* setup io resource */
- resource->res1.type = ACPI_RESOURCE_TYPE_IO;
- resource->res1.length = sizeof(struct acpi_resource);
- memcpy(&resource->res1.data.io, &ioport->io1,
- sizeof(struct acpi_resource_io));
- /* setup irq resource */
- resource->res2.type = ACPI_RESOURCE_TYPE_IRQ;
- resource->res2.length = sizeof(struct acpi_resource);
- memcpy(&resource->res2.data.irq, &irq->irq, sizeof(struct acpi_resource_irq));
- /* we requested a shared irq */
- resource->res2.data.irq.shareable = ACPI_SHARED;
- resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG;
- resource->res3.length = sizeof(struct acpi_resource);
- }
- /* Attempt to set the resource */
- printk( KERN_NOTICE "[%s] Evaluating _SRS\n", KBUILD_MODNAME );
- status = acpi_set_current_resources(device->handle, &buffer);
- /* check for total failure */
- if (ACPI_FAILURE(status)) {
- pr_err("Error evaluating _SRS\n");
- result = -ENODEV;
- goto end;
- }
- /* Necessary device initializations calls (from sonypi) */
- sony_pic_call1(0x82);
- sony_pic_call2(0x81, 0xff);
- sony_pic_call1(compat ? 0x92 : 0x82);
- end:
- kfree(resource);
- return result;
- }
- //Disable the spic device by calling its _DIS method
- static int sony_pic_disable( struct acpi_device *device ){
- acpi_status ret = acpi_evaluate_object( device->handle, "_DIS", NULL, NULL );
- if( ACPI_FAILURE(ret) && ret != AE_NOT_FOUND ) return -ENXIO;
- printk( KERN_NOTICE "[%s] Device disabled\n", KBUILD_MODNAME );
- return 0;
- }
- static int sony_pic_add( struct acpi_device* device ) {
- int result;
- struct sony_pic_ioport *io, *tmp_io;
- struct sony_pic_irq *irq, *tmp_irq;
-
- printk( KERN_NOTICE "[%s] SPIC setup...\n", KBUILD_MODNAME );
-
- spic_dev.acpi_dev = device;
- strcpy(acpi_device_class(device), "sony/hotkey");
- sony_pic_detect_device_type(&spic_dev);
- mutex_init(&spic_dev.lock);
- /* read _PRS resources */
- result = sony_pic_possible_resources( device );
- if( result ){
- pr_err( "[%s]Unable to read possible resources\n", KBUILD_MODNAME );
- goto err_free_resources;
- }
- //setup input device
- result = vgnux_register_input();
- if( result ){
- pr_err("[%s]Unable to create input device\n", KBUILD_MODNAME );
- goto err_free_resources;
- }
- result = sonypi_compat_init();
- if( result ) goto err_remove_input;
- /* request io port */
- list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
- if (request_region(io->io1.minimum, io->io1.address_length,
- "Sony Programmable I/O Device")) {
- printk( KERN_NOTICE "[%s] I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
- KBUILD_MODNAME,
- io->io1.minimum,
- io->io1.maximum,
- io->io1.address_length
- );
- /* Type 1 have 2 ioports */
- if (io->io2.minimum) {
- if (request_region(io->io2.minimum,
- io->io2.address_length,
- "Sony Programmable I/O Device")) {
- printk( KERN_NOTICE "[%s] I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
- KBUILD_MODNAME,
- io->io2.minimum,
- io->io2.maximum,
- io->io2.address_length
- );
- spic_dev.cur_ioport = io;
- break;
- }
- else {
- printk( KERN_ERR "[%s] Unable to get I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
- KBUILD_MODNAME,
- io->io2.minimum,
- io->io2.maximum,
- io->io2.address_length
- );
- release_region( io->io1.minimum, io->io1.address_length );
- }
- }
- else {
- spic_dev.cur_ioport = io;
- break;
- }
- }
- }
- if (!spic_dev.cur_ioport) {
- pr_err( "[%s]Failed to request_region\n", KBUILD_MODNAME );
- result = -ENODEV;
- goto err_remove_compat;
- }
- /* request IRQ */
- list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
- if( !request_irq(irq->irq.interrupts[0], sony_pic_irq_handler, 0, KBUILD_MODNAME, &spic_dev) ){
- printk( KERN_NOTICE "[%s] IRQ: %d - triggering: %d - polarity: %d - shr: %d\n",
- KBUILD_MODNAME,
- irq->irq.interrupts[0],
- irq->irq.triggering,
- irq->irq.polarity,
- irq->irq.shareable
- );
- spic_dev.cur_irq = irq;
- break;
- }
- }
- if (!spic_dev.cur_irq) {
- pr_err( "[%s]Failed to request_irq\n", KBUILD_MODNAME );
- result = -ENODEV;
- goto err_release_region;
- }
- /* set resource status _SRS */
- result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
- if ( result ) {
- printk( KERN_ERR "[%s] Couldn't enable device\n", KBUILD_MODNAME );
- goto err_free_irq;
- }
- spic_dev.bluetooth_power = -1;
- /* create device attributes */
- result = sony_pf_add();
- if (result) goto err_disable_device;
- result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
- if (result) goto err_remove_pf;
- pr_info( "[%s] SPIC setup done.\n", KBUILD_MODNAME );
- return 0;
- err_remove_pf:
- sony_pf_remove();
- err_disable_device:
- sony_pic_disable(device);
- err_free_irq:
- free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
- err_release_region:
- release_region(spic_dev.cur_ioport->io1.minimum, spic_dev.cur_ioport->io1.address_length);
- if (spic_dev.cur_ioport->io2.minimum)
- release_region(spic_dev.cur_ioport->io2.minimum, spic_dev.cur_ioport->io2.address_length);
- err_remove_compat:
- sonypi_compat_exit();
- err_remove_input:
- vgnux_unregister_input();
- err_free_resources:
- list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
- list_del(&io->list);
- kfree(io);
- }
- list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
- list_del(&irq->list);
- kfree(irq);
- }
- spic_dev.cur_ioport = NULL;
- spic_dev.cur_irq = NULL;
- return result;
- }
- static int sony_pic_remove( struct acpi_device* device ){
- struct sony_pic_ioport *io, *tmp_io;
- struct sony_pic_irq *irq, *tmp_irq;
- if( sony_pic_disable(device) ) {
- pr_err("Couldn't disable device\n");
- return -ENXIO;
- }
- free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev);
- release_region(spic_dev.cur_ioport->io1.minimum, spic_dev.cur_ioport->io1.address_length);
- if (spic_dev.cur_ioport->io2.minimum)
- release_region(spic_dev.cur_ioport->io2.minimum, spic_dev.cur_ioport->io2.address_length);
- sonypi_compat_exit();
- vgnux_unregister_input();
- /* pf attrs */
- sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
- sony_pf_remove();
- list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) {
- list_del(&io->list);
- kfree(io);
- }
- list_for_each_entry_safe(irq, tmp_irq, &spic_dev.interrupts, list) {
- list_del(&irq->list);
- kfree(irq);
- }
- spic_dev.cur_ioport = NULL;
- spic_dev.cur_irq = NULL;
- printk( KERN_NOTICE "[%s] "SONY_PIC_DRIVER_NAME " removed.\n", KBUILD_MODNAME );
- return 0;
- }
- #ifdef CONFIG_PM_SLEEP
- static int sony_pic_suspend( struct device* dev ){
- if( sony_pic_disable(to_acpi_device(dev)) ) return -ENXIO;
- return 0;
- }
- static int sony_pic_resume( struct device* dev ){
- sony_pic_enable( to_acpi_device(dev), spic_dev.cur_ioport, spic_dev.cur_irq );
- return 0;
- }
- #endif
- /********************
- * MODULE INIT *
- ********************/
- static int __init onLoad( void ){
-
- int result = 0;
-
- printk( KERN_NOTICE "%s is here.\n", KBUILD_MODNAME );
-
- if( !dmi_check_system( sonypi_dmi_table ) ){
- printk( KERN_NOTICE "[%s] Compatable hardware not found.\n", KBUILD_MODNAME );
- return -ENODEV;
- }
-
- result = acpi_bus_register_driver( &sony_pic_driver );
- if( result ) printk( KERN_ERR "[%s] Unable to register SPIC driver\n", KBUILD_MODNAME );
- return result;
- }
- static void __exit onUnload( void ){
- acpi_bus_unregister_driver( &sony_pic_driver );
- printk( KERN_NOTICE "%s has been unloaded.\n", KBUILD_MODNAME );
- }
- module_init( onLoad );
- module_exit( onUnload );
- MODULE_LICENSE("GPL");
- MODULE_DEVICE_TABLE( acpi, sony_pic_device_ids );
|